diff --git a/.coverage-fix.tmp b/.coverage-fix.tmp new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/.coverage-fix.tmp @@ -0,0 +1 @@ + diff --git a/et --hard 25755a4c b/et --hard 25755a4c new file mode 100644 index 0000000000..a863f0b2f2 --- /dev/null +++ b/et --hard 25755a4c @@ -0,0 +1,80 @@ +e00e5f28 (HEAD -> fix-cse, origin/master, origin/HEAD, gigopogo/fix-cse, master) HEAD@{0}: reset: moving to HEAD~1 +25755a4c HEAD@{1}: commit: Version 1 +e00e5f28 (HEAD -> fix-cse, origin/master, origin/HEAD, gigopogo/fix-cse, master) HEAD@{2}: reset: moving to master +7a6fcb7d (gigopogo/fix/cse-layout-machine) HEAD@{3}: checkout: moving from master to fix-cse +e00e5f28 (HEAD -> fix-cse, origin/master, origin/HEAD, gigopogo/fix-cse, master) HEAD@{4}: commit: Fixed the error where the frames WERE not moving due to the Layout team's invariant! +99f83010 HEAD@{5}: commit: Fixed the sentry bot suggestion +2ef3c484 HEAD@{6}: commit: Fixed tsc error +50f2b774 HEAD@{7}: pull: Fast-forward +d6c68817 HEAD@{8}: pull --rebase origin master (finish): returning to refs/heads/master +d6c68817 HEAD@{9}: pull --rebase origin master (pick): Fixed the following errors and implemented suggestions +26345cb6 HEAD@{10}: pull --rebase origin master (start): checkout 26345cb6b61bda45de0f47c64edef54e2dc4cfc8 +b12755a3 HEAD@{11}: commit: Fixed the following errors and implemented suggestions +44e1f30c HEAD@{12}: checkout: moving from fix-cse to master +7a6fcb7d (gigopogo/fix/cse-layout-machine) HEAD@{13}: reset: moving to HEAD +7a6fcb7d (gigopogo/fix/cse-layout-machine) HEAD@{14}: checkout: moving from master to fix-cse +44e1f30c HEAD@{15}: commit: Changed from Hide -> Clear and the icon +2c3897cd HEAD@{16}: checkout: moving from Hulk_fix to master +953df696 (Hulk_fix) HEAD@{17}: commit: Fixed the formatting! +d9ce60bf HEAD@{18}: pull: Fast-forward +039f07de HEAD@{19}: reset: moving to HEAD +039f07de HEAD@{20}: commit: Hulk Fix! +5e84b1d7 (upstream/master) HEAD@{21}: Branch: renamed refs/heads/backup-branch to refs/heads/Hulk_fix +5e84b1d7 (upstream/master) HEAD@{23}: reset: moving to upstream/master +3b75e828 HEAD@{24}: merge upstream/master: Merge made by the 'ort' strategy. +22d7859d HEAD@{25}: checkout: moving from master to backup-branch +2c3897cd HEAD@{26}: commit: Fix : Toggle -> One time cleanup +39a1ac0e HEAD@{27}: commit: Fix : CI format errors and made it from checkbox -> onClick button! +321f22df HEAD@{28}: commit: Fix : Removed gaps +f02260af HEAD@{29}: commit: Added the functionality for toggle of dead vs ONLY live for +baebfb5f HEAD@{30}: merge backup-branch: Merge made by the 'ort' strategy. +5e84b1d7 (upstream/master) HEAD@{31}: reset: moving to upstream/master +22d7859d HEAD@{32}: checkout: moving from backup-branch to master +22d7859d HEAD@{33}: checkout: moving from master to backup-branch +22d7859d HEAD@{34}: commit: Added the removeDeadFrames feature +3908dbea HEAD@{35}: reset: moving to upstream/master +5e84b1d7 (upstream/master) HEAD@{36}: reset: moving to HEAD +5e84b1d7 (upstream/master) HEAD@{37}: pull: Fast-forward +96ce8d89 (gigopogo/master) HEAD@{38}: checkout: moving from shortCircuitFix/master to master +176f3107 (origin/shortCircuitFix/master) HEAD@{39}: commit: Fixed the SENTRY bot error +0e03ed5a HEAD@{40}: commit: Fixed the issue described at #3574 +3908dbea HEAD@{41}: reset: moving to upstream/master +96ce8d89 (gigopogo/master) HEAD@{42}: checkout: moving from master to shortCircuitFix/master +96ce8d89 (gigopogo/master) HEAD@{43}: reset: moving to upstream/master +8fb394fe HEAD@{44}: reset: moving to origin/master +35fd4244 HEAD@{45}: checkout: moving from pr-3575 to master +d406e33d (upstream/partial-revert-3570) HEAD@{46}: checkout: moving from master to pr-3575 +35fd4244 HEAD@{47}: checkout: moving from pr-3575 to master +d406e33d (upstream/partial-revert-3570) HEAD@{48}: checkout: moving from master to pr-3575 +35fd4244 HEAD@{49}: checkout: moving from pr-3575 to master +d406e33d (upstream/partial-revert-3570) HEAD@{50}: checkout: moving from fix/liveness-clean to pr-3575 +35fd4244 HEAD@{51}: checkout: moving from master to fix/liveness-clean +35fd4244 HEAD@{52}: reset: moving to upstream/master +8fb394fe HEAD@{53}: rebase (abort): returning to refs/heads/master +35fd4244 HEAD@{54}: pull --rebase upstream master (start): checkout 35fd42446edc8775d4aee2013dccda960875e750 +8fb394fe HEAD@{55}: checkout: moving from master to master +8fb394fe HEAD@{56}: commit: CI errors fixed commit TRIAL +0a39954d HEAD@{57}: commit: Fixed and removed all the needless import statements and other errors in seperate files! +132b52b6 HEAD@{58}: commit: CI errors for formatting fixed +391f6c4a HEAD@{59}: commit: Fixed the yarn.lock file according to the CI dependencies and req +6b32f2b4 HEAD@{60}: commit: yarn test fail errors in CI FIXED +a3c12ce3 HEAD@{61}: checkout: moving from master to master +a3c12ce3 HEAD@{62}: commit: Fixed the CI yarn test AUTO errors on Nav Bar +560b326c HEAD@{63}: commit: PR CI auto yarn TEST conflict RESOLVED +a13e801b HEAD@{64}: reset: moving to HEAD~1 +dfc9e353 HEAD@{65}: commit: Fixed yarn test CI auto errors for PR conflicts +a13e801b HEAD@{66}: checkout: moving from master to master +a13e801b HEAD@{67}: commit (merge): PR Merge Conflic RESOLVE +e0e3308e HEAD@{68}: pull: Fast-forward +f1f853c6 HEAD@{69}: commit: Final_Draft-I PR - I +4d01e792 HEAD@{70}: reset: moving to HEAD +4d01e792 HEAD@{71}: reset: moving to HEAD +4d01e792 HEAD@{72}: commit: Week 5 Pt 1 BUG FIX +6790c5b7 HEAD@{73}: reset: moving to HEAD +6790c5b7 HEAD@{74}: commit: Week 4 Pt III +43447418 HEAD@{75}: commit: WEEK - 4 Pt II +42ff8a64 HEAD@{76}: commit (amend): WEEK 4 +33c788d4 HEAD@{77}: commit: This commit made the following changes +d90d96fa HEAD@{78}: pull: Fast-forward +902b5eb6 HEAD@{79}: commit: WEEK - 3 +013fd0a9 HEAD@{80}: clone: from https://github.com/Akshay-2007-1/CSE_liveness_frontend.git diff --git a/src/features/cseMachine/CseMachine.tsx b/src/features/cseMachine/CseMachine.tsx index 30bc4a32e9..2e68fb8db9 100644 --- a/src/features/cseMachine/CseMachine.tsx +++ b/src/features/cseMachine/CseMachine.tsx @@ -19,8 +19,9 @@ export default class CseMachine { public static setEditorHighlightedLines: SetEditorHighlightedLines; /** callback function to update the step limit exceeded state in the SideContentCseMachine component */ private static setIsStepLimitExceeded: SetisStepLimitExceeded; - // This stores the "Ghost Run (last step x coordinates)" snapshot - public static masterLayout: LayoutCache | null = null; + // Ghost layout snapshots, separated by mode to keep coordinates fixed within each mode. + public static normalLayoutCache: LayoutCache | null = null; + public static printLayoutCache: LayoutCache | null = null; private static printableMode: boolean = false; private static controlStash: boolean = false; // TODO: discuss if the default should be true private static stackTruncated: boolean = false; @@ -51,6 +52,8 @@ export default class CseMachine { Layout.currentStackTruncLight = undefined; Layout.prevLayout = undefined; Layout.key = 0; + CseMachine.normalLayoutCache = null; + CseMachine.printLayoutCache = null; } // added for center alignment public static toggleCenterAlignment(): void { @@ -74,6 +77,18 @@ export default class CseMachine { public static getCenterAlignment(): boolean { return CseMachine.centerAlignment; } + public static getMasterLayout(): LayoutCache | null { + return CseMachine.getPrintableMode() + ? CseMachine.printLayoutCache + : CseMachine.normalLayoutCache; + } + public static setMasterLayout(cache: LayoutCache): void { + if (CseMachine.getPrintableMode()) { + CseMachine.printLayoutCache = cache; + } else { + CseMachine.normalLayoutCache = cache; + } + } public static isControl(): boolean { return this.control ? !this.control.isEmpty() : false; @@ -117,19 +132,24 @@ export default class CseMachine { context.runtime.stash, context.chapter ); - // get ghost layout on first run (when user press run and code changes) - if (!CseMachine.masterLayout) { - Layout.setContext( - context.runtime.environmentTree as EnvTree, - context.runtime.control, - context.runtime.stash, - context.chapter - ); - CseMachine.masterLayout = Layout.getLayoutPositions(this.controlStash); + + // Build ghost layout cache lazily per mode. + if (!CseMachine.normalLayoutCache || !CseMachine.printLayoutCache) { + // fill up both lookup table of normal mode and printable mode + const originalMode = CseMachine.getPrintableMode(); + + CseMachine.printableMode = true; + CseMachine.setMasterLayout(Layout.getLayoutPositions(this.controlStash)); + + CseMachine.printableMode = false; + CseMachine.setMasterLayout(Layout.getLayoutPositions(this.controlStash)); + + // 3. Restore the user's actual mode setting + CseMachine.printableMode = originalMode; } // Apply Fixed Positions - if (CseMachine.masterLayout) { + if (CseMachine.getMasterLayout()) { Layout.applyFixedPositions(); } this.setVis(Layout.draw()); @@ -144,7 +164,10 @@ export default class CseMachine { // if center alignment is toggled, change the alignment and redraw the diagram with new coordinates if (this.centerAlignmentToggled) { Layout.setContext(CseMachine.environmentTree, CseMachine.control, CseMachine.stash); - if (CseMachine.masterLayout) { + if (!CseMachine.getMasterLayout()) { + CseMachine.setMasterLayout(Layout.getLayoutPositions(this.controlStash)); + } + if (CseMachine.getMasterLayout()) { Layout.applyFixedPositions(); } this.setVis(Layout.draw()); @@ -193,7 +216,7 @@ export default class CseMachine { this.setVis(Layout.currentDark); } else { Layout.setContext(CseMachine.environmentTree, CseMachine.control, CseMachine.stash); - if (CseMachine.masterLayout) { + if (CseMachine.getMasterLayout()) { Layout.applyFixedPositions(); } this.setVis(Layout.draw()); @@ -216,7 +239,6 @@ export default class CseMachine { CseMachine.stash = undefined; } CseMachine.setClearDeadFrames(false); - CseMachine.clearCachedLayouts(); this.clear(); } } diff --git a/src/features/cseMachine/CseMachineConfig.ts b/src/features/cseMachine/CseMachineConfig.ts index c91048cfcf..67663e702b 100644 --- a/src/features/cseMachine/CseMachineConfig.ts +++ b/src/features/cseMachine/CseMachineConfig.ts @@ -20,6 +20,9 @@ export const Config = Object.freeze({ FnInnerRadius: 3, FnTooltipOpacity: 0.3, FnTooltipTextPadding: 5, + FnDescriptionMaxWidth: 150, + FnDescriptionMaxHeight: 60, + FnDescriptionRevealOffsetY: 8, DataMinWidth: 20, DataUnitWidth: 40, diff --git a/src/features/cseMachine/CseMachineLayout.tsx b/src/features/cseMachine/CseMachineLayout.tsx index e6a71fa7cb..35ddf6dc1f 100644 --- a/src/features/cseMachine/CseMachineLayout.tsx +++ b/src/features/cseMachine/CseMachineLayout.tsx @@ -664,7 +664,8 @@ export class Layout { const controlStashOffset = ControlStashConfig.ControlPosX + ControlStashConfig.ControlItemWidth; const offset = controlStash ? controlStashOffset : 0; - const currWidth = level.width() + frames[frames.length - 1].totalDataWidth; + // `level.width()` already includes the last frame's right-side overflow. + const currWidth = level.width(); cache.largestWidth = Math.max(cache.largestWidth, currWidth); frames.forEach(frame => { cache.frames.set(frame.environment.id, frame.x() - offset); @@ -683,7 +684,7 @@ export class Layout { if (Layout.clearDeadFrames) { return undefined; } - const cache = CseMachine.masterLayout; + const cache = CseMachine.getMasterLayout(); if (cache && cache.frames.has(envId)) { const fixedX = cache.frames.get(envId)!; // add offset for control stash and center alignment @@ -703,10 +704,10 @@ export class Layout { * Reassign x coordinate of every frame to their predetermined position by calling getGhostFrameX. */ static applyFixedPositions() { - if (Layout.clearDeadFrames || !CseMachine.masterLayout) { + if (Layout.clearDeadFrames || !CseMachine.getMasterLayout()) { return; } - const cache = CseMachine.masterLayout!; // getLayoutPositions() must have been called before + const cache = CseMachine.getMasterLayout()!; // getLayoutPositions() must have been called before Layout.levels.forEach(level => { level.frames.forEach(frame => { const id = frame.environment.id; diff --git a/src/features/cseMachine/CseMachineUtils.ts b/src/features/cseMachine/CseMachineUtils.ts index b95d0b0339..6dc827dc76 100644 --- a/src/features/cseMachine/CseMachineUtils.ts +++ b/src/features/cseMachine/CseMachineUtils.ts @@ -735,6 +735,53 @@ export const truncateText = (programStr: string, maxWidth: number, maxHeight: nu return [...lines, Config.Ellipsis].join('\n'); }; +const appendSuffixWithinWidth = (line: string, suffix: string, maxWidth: number): string => { + const ellipsis = Config.Ellipsis; + const ellipsisIndex = line.lastIndexOf(ellipsis); + + if (ellipsisIndex === -1) { + return line; + } + + let prefix = line.slice(0, ellipsisIndex); + let candidate = `${prefix} ${ellipsis + suffix}`; + + while (prefix && getTextWidth(candidate) > maxWidth) { + prefix = prefix.slice(0, -1); + candidate = `${prefix} ${ellipsis + suffix}`; + } + + return candidate; +}; + +export const truncateFunctionTooltip = ( + tooltip: string, + maxWidth: number, + maxHeight: number +): string => { + const truncatedTooltip = truncateText(tooltip, maxWidth, maxHeight); + + if (truncatedTooltip === tooltip) { + return truncatedTooltip; + } + + const lines = truncatedTooltip.split('\n'); + const originalLines = tooltip.split('\n'); + + const paramsLineIndex = originalLines.findIndex(line => line.startsWith('params:')); + if (paramsLineIndex !== -1 && lines[paramsLineIndex]?.endsWith(Config.Ellipsis)) { + lines[paramsLineIndex] = appendSuffixWithinWidth(lines[paramsLineIndex], ')', maxWidth); + } + + const bodyClosingLineIndex = originalLines.findLastIndex(line => line.trim() === '}'); + if (bodyClosingLineIndex !== -1 && bodyClosingLineIndex >= lines.length) { + const lastLineIndex = lines.length - 1; + lines[lastLineIndex] = appendSuffixWithinWidth(lines[lastLineIndex], ' }', maxWidth); + } + + return lines.join('\n'); +}; + /** * Typeguard for Instr to distinguish between program statements and instructions. * The typeguard from js-slang cannot be used due to Typescript raising some weird errors diff --git a/src/features/cseMachine/components/Binding.tsx b/src/features/cseMachine/components/Binding.tsx index f4ee57e72b..0a4fb3dad6 100644 --- a/src/features/cseMachine/components/Binding.tsx +++ b/src/features/cseMachine/components/Binding.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import CseMachine from '../CseMachine'; import { Config } from '../CseMachineConfig'; import { Layout } from '../CseMachineLayout'; import { Data } from '../CseMachineTypes'; @@ -9,7 +10,6 @@ import { GenericArrow } from './arrows/GenericArrow'; import { Frame } from './Frame'; import { Text } from './Text'; import { ArrayValue } from './values/ArrayValue'; -import { ContValue } from './values/ContValue'; import { FnValue } from './values/FnValue'; import { GlobalFnValue } from './values/GlobalFnValue'; import { PrimitiveValue } from './values/PrimitiveValue'; @@ -68,20 +68,24 @@ export class Binding extends Visible { this.keyYOffset = keyYOffset; this.key = new Text(this.keyString, this.x(), this.y() + keyYOffset, { faded: !this.isLive }); + const printFnDescriptionHeight = + CseMachine.getPrintableMode() && + isMainReference(this.value, this) && + (this.value instanceof FnValue || this.value instanceof GlobalFnValue) + ? this.value.printDescriptionHeight + + this.value.printDescriptionOffsetY + + this.value.printDescriptionBottomGap + + Config.TextPaddingY / 2 + : 0; + // derive the width from the right bound of the value - this._width = isMainReference(this.value, this) - ? this.value.x() - - this.x() + - (this.value instanceof FnValue || - this.value instanceof GlobalFnValue || - this.value instanceof ContValue - ? this.value.tooltipWidth - : 0) - : this.key.width(); + this._width = isMainReference(this.value, this) ? this.value.x() - this.x() : this.key.width(); this._height = Math.max( this.key.height(), - this.value instanceof ArrayValue ? this.value.totalHeight : this.value.height() + this.value instanceof ArrayValue + ? this.value.totalHeight + : this.value.height() + printFnDescriptionHeight ); if (this.isDummyBinding && !isMainReference(this.value, this)) { diff --git a/src/features/cseMachine/components/Frame.tsx b/src/features/cseMachine/components/Frame.tsx index 0506631090..89d06788e5 100644 --- a/src/features/cseMachine/components/Frame.tsx +++ b/src/features/cseMachine/components/Frame.tsx @@ -15,6 +15,7 @@ import { isClosure, isDataArray, isDummyKey, + isMainReference, isPrimitiveData, isSourceObject, isUnassigned @@ -25,6 +26,10 @@ import { GenericArrow } from './arrows/GenericArrow'; import { Binding } from './Binding'; import { Level } from './Level'; import { Text } from './Text'; +import { ArrayValue } from './values/ArrayValue'; +import { ContValue } from './values/ContValue'; +import { FnValue } from './values/FnValue'; +import { GlobalFnValue } from './values/GlobalFnValue'; import { Visible } from './Visible'; const frameNames = new Map([ @@ -45,7 +50,7 @@ export class Frame extends Visible implements IHoverable { /** total height = frame height + frame title height */ readonly totalHeight: number; - /** width of this frame + max width of the bound values */ + /** width budget of this frame block (excluding right-side data overflow) */ readonly totalWidth: number; /** width of data beside frame */ @@ -138,9 +143,9 @@ export class Frame extends Visible implements IHoverable { entries.push([`${i++}`, descriptor]); } - // Find the correct width of the frame before creating the bindings + // Find the correct width of the frame before creating the bindings. + // This pass sizes only the frame body (text and primitive values inside the frame). this._width = Config.FrameMinWidth; - let totalWidth = this._width + Config.FrameMinGapX; for (const [key, data] of entries) { if (isDummyKey(key)) continue; const constant = @@ -160,66 +165,6 @@ export class Frame extends Visible implements IHoverable { ); } this._width = Math.max(this._width, bindingTextWidth + Config.FramePaddingX * 2); - - // calculate width needed for data spacing to avoid collision - if (isDataArray(data.value)) { - // helper function to calculate an array width - const getChainWidth = (startNode: any[]): number => { - let w = 0; - let curr = startNode; - const seen = new Set(); - - while (isDataArray(curr)) { - // escape from circular lists - if (seen.has(curr)) break; - seen.add(curr); - w += curr.length * Config.DataUnitWidth; - const lastIndex = curr.length - 1; - const lastElement = curr[lastIndex]; - - if (isDataArray(lastElement)) { - w += Config.DataUnitWidth; - curr = lastElement; - } else { - break; - } - } - return w; - }; - - let maxWidth = 0; - let currentSpineX = 0; - let curr = data.value; - const seenSpine = new Set(); - - while (isDataArray(curr)) { - if (seenSpine.has(curr)) break; - seenSpine.add(curr); - const blockWidth = curr.length * Config.DataUnitWidth; - const head = curr[0]; - - if (isDataArray(head)) { - const branchWidth = getChainWidth(head); - maxWidth = Math.max(maxWidth, currentSpineX + branchWidth); - } - - currentSpineX += blockWidth; - - const lastIndex = curr.length - 1; - const lastElement = curr[lastIndex]; - - if (isDataArray(lastElement)) { - currentSpineX += Config.DataUnitWidth; - curr = lastElement; - } else { - maxWidth = Math.max(maxWidth, currentSpineX); - break; - } - } - - this.totalDataWidth = Math.max(this.totalDataWidth, maxWidth); - } - totalWidth = Math.max(totalWidth, this._width + Config.FrameMinGapX); } // Create all the bindings and values @@ -240,9 +185,33 @@ export class Frame extends Visible implements IHoverable { ); prevBinding = currBinding; this.bindings.push(currBinding); - totalWidth = Math.max(totalWidth, currBinding.width() + Config.FramePaddingX); } - this.totalWidth = totalWidth; + + // Post-process using actual created values to get robust spacing for nested arrays/functions. + // `totalDataWidth` is measured strictly as overflow beyond the frame's right edge. + const frameRightX = this.x() + this.width(); + for (const binding of this.bindings) { + const value = binding.value; + if (!isMainReference(value, binding)) continue; + + let valueRightX: number | undefined; + if (value instanceof ArrayValue) { + valueRightX = value.x() + value.totalWidth; + } else if (value instanceof FnValue || value instanceof GlobalFnValue) { + valueRightX = CseMachine.getPrintableMode() + ? value.x() + value.totalWidth + : value.x() + value.width(); + } else if (value instanceof ContValue) { + valueRightX = value.x() + value.width() + value.tooltipWidth; + } + + if (valueRightX !== undefined) { + const overflow = Math.max(0, valueRightX - frameRightX); + this.totalDataWidth = Math.max(this.totalDataWidth, overflow); + } + } + + this.totalWidth = this.width(); // derive the height of the frame from the the position of the last binding this._height = prevBinding diff --git a/src/features/cseMachine/components/Level.tsx b/src/features/cseMachine/components/Level.tsx index 28eff87fce..f8da0471a2 100644 --- a/src/features/cseMachine/components/Level.tsx +++ b/src/features/cseMachine/components/Level.tsx @@ -46,8 +46,13 @@ export class Level extends Visible { 0 ); const lastFrame = this.frames[this.frames.length - 1]; - // derive the width of this level from the last frame - this._width = lastFrame.x() + lastFrame.totalWidth - this.x() + Config.LevelPaddingX; + // derive the width of this level from the last frame and its right-side data overflow + this._width = + lastFrame.x() + + lastFrame.totalWidth + + lastFrame.totalDataWidth - + this.x() + + Config.LevelPaddingX; } destroy() { diff --git a/src/features/cseMachine/components/values/ArrayValue.tsx b/src/features/cseMachine/components/values/ArrayValue.tsx index 6eebb89e28..cb2de77a14 100644 --- a/src/features/cseMachine/components/values/ArrayValue.tsx +++ b/src/features/cseMachine/components/values/ArrayValue.tsx @@ -2,6 +2,7 @@ import { KonvaEventObject } from 'konva/lib/Node'; import React from 'react'; import { Group } from 'react-konva'; +import CseMachine from '../../CseMachine'; import { Config } from '../../CseMachineConfig'; import { Layout } from '../../CseMachineLayout'; import { DataArray, IHoverable, ReferenceType } from '../../CseMachineTypes'; @@ -11,6 +12,7 @@ import { ArrayUnit } from '../ArrayUnit'; import { Binding } from '../Binding'; import { Frame } from '../Frame'; import { FnValue } from './FnValue'; +import { GlobalFnValue } from './GlobalFnValue'; import { Value } from './Value'; /** this class encapsulates an array value in source, @@ -71,20 +73,36 @@ export class ArrayValue extends Value implements IHoverable { // Update total width and height for values that are drawn next to the array if ( - (unit.value instanceof ArrayValue || unit.value instanceof FnValue) && + (unit.value instanceof ArrayValue || + unit.value instanceof FnValue || + unit.value instanceof GlobalFnValue) && isMainReference(unit.value, unit) ) { + const childWidth = + unit.value instanceof ArrayValue + ? unit.value.totalWidth + : CseMachine.getPrintableMode() + ? unit.value.totalWidth + : unit.value.width(); + + const bottomY = + unit.value instanceof ArrayValue + ? unit.value.y() + unit.value.totalHeight + : CseMachine.getPrintableMode() + ? unit.value.y() + + Config.FnRadius + + Config.TextMargin + + unit.value.printDescriptionOffsetY + + unit.value.printDescriptionHeight + + unit.value.printDescriptionBottomGap + : unit.value.y() + unit.value.height() / 2; + this.totalWidth = Math.max( this.totalWidth, - unit.value.totalWidth + + childWidth + (i === this.data.length - 1 ? (i + 2) * Config.DataUnitWidth : i * Config.DataUnitWidth) ); - this.totalHeight = Math.max( - this.totalHeight, - unit.value.y() + - (unit.value instanceof ArrayValue ? unit.value.totalHeight : unit.value.height() / 2) - - unit.y() - ); + this.totalHeight = Math.max(this.totalHeight, bottomY - unit.y()); } this.units[i] = unit; diff --git a/src/features/cseMachine/components/values/FnValue.tsx b/src/features/cseMachine/components/values/FnValue.tsx index 720544fe19..84ab7bc514 100644 --- a/src/features/cseMachine/components/values/FnValue.tsx +++ b/src/features/cseMachine/components/values/FnValue.tsx @@ -20,11 +20,13 @@ import { fadedTextColor, getBodyText, getParamsText, + getTextHeight, getTextWidth, isMainReference, isStreamFn, setHoveredCursor, - setUnhoveredCursor + setUnhoveredCursor, + truncateFunctionTooltip } from '../../CseMachineUtils'; import { ArrowFromFn } from '../arrows/ArrowFromFn'; import { Binding } from '../Binding'; @@ -46,13 +48,19 @@ export class FnValue extends Value implements IHoverable { readonly tooltipWidth: number; readonly exportTooltip: string; readonly exportTooltipWidth: number; + readonly isTooltipTruncated: boolean; + readonly printDescriptionHeight: number; + readonly printDescriptionOffsetY: number; + readonly printDescriptionBottomGap: number; /** width of the closure circles + label */ readonly totalWidth: number; readonly labelRef: RefObject