From cde3212b1eb98e3c8d814838e06b3d6868d07bf5 Mon Sep 17 00:00:00 2001 From: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> Date: Tue, 24 Jan 2023 15:44:56 -0500 Subject: [PATCH] Handle super long symbols in the cfg (#4616) --- lib/cfg.js | 2 +- package.json | 2 +- static/panes/cfg-view.ts | 68 ++++++++++++++++++++++++++++++++++++- static/styles/explorer.scss | 12 +++++++ 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/lib/cfg.js b/lib/cfg.js index d3d14f9b8e9..7b14cddcc5e 100644 --- a/lib/cfg.js +++ b/lib/cfg.js @@ -154,7 +154,7 @@ function splitToBasicBlocks(asmArr, range, isEnd, isJmp) { const functionName = asmArr[first].text; ++first; - let rangeBb = {nameId: functionName.substr(0, 50), start: first, end: null, actionPos: []}; + let rangeBb = {nameId: functionName, start: first, end: null, actionPos: []}; const result = []; const newRangeWith = function (oldRange, nameId, start) { diff --git a/package.json b/package.json index f29ba2545cb..3461bf74d85 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "@sentry/node": "^7.28.1", "@types/body-parser": "^1.19.2", "@types/file-saver": "^2.0.5", - "@types/js-cookie": "^3.0.2", "@types/http-proxy": "^1.17.9", + "@types/js-cookie": "^3.0.2", "@types/request": "^2.48.8", "aws-sdk": "^2.1048.0", "big-integer": "^1.6.51", diff --git a/static/panes/cfg-view.ts b/static/panes/cfg-view.ts index d799990c8ad..27943d3bfe7 100644 --- a/static/panes/cfg-view.ts +++ b/static/panes/cfg-view.ts @@ -126,6 +126,7 @@ export class Cfg extends Pane { state: CfgState & PaneState; layout: GraphLayoutCore; bbMap: Record = {}; + tooltipOpen = false; readonly extraTransforms: string; fictitiousGraphContainer: HTMLDivElement; fictitiousBlockContainer: HTMLDivElement; @@ -267,6 +268,15 @@ export class Cfg extends Pane { this.exportSVGButton.on('click', () => { this.exportSVG(); }); + // Dismiss tooltips if you click elsewhere - trigger: focus isn't working for some reason + $('body').on('click', e => { + if (this.tooltipOpen) { + if (!e.target.classList.contains('fold') && $(e.target).parents('.popover.in').length === 0) { + this.tooltipOpen = false; + $('.fold').popover('hide'); + } + } + }); } async exportPNG() { @@ -331,7 +341,61 @@ export class Cfg extends Pane { for (const node of fn.nodes) { const div = document.createElement('div'); div.classList.add('block'); - div.innerHTML = await monaco.editor.colorize(node.label, 'asm', MonacoConfig.extendConfig({})); + const folded_lines: number[] = []; + const raw_lines = node.label.split('\n'); + const highlighted_asm_untrimmed = await monaco.editor.colorize( + raw_lines.join('\n'), + 'asm', + MonacoConfig.extendConfig({}) + ); + const highlighted_asm = await monaco.editor.colorize( + raw_lines + .map((line, i) => { + if (line.length <= 100) { + return line; + } else { + folded_lines.push(i); + return line.slice(0, 100); + } + }) + .join('\n'), + 'asm', + MonacoConfig.extendConfig({}) + ); + const untrimmed_lines = highlighted_asm_untrimmed.split('
'); + const lines = highlighted_asm.split('
'); + // highlighted asm has a blank line at the end + assert(raw_lines.length === untrimmed_lines.length - 1); + assert(raw_lines.length === lines.length - 1); + for (const i of folded_lines) { + lines[i] += `(\s| )<\/span>/, '>') // Hacky solution to remove whitespace at the start + }" aria-describedby="wtf">⋯`; + } + div.innerHTML = lines.join('
'); + for (const fold of div.getElementsByClassName('fold')) { + $(fold) + .popover({ + content: unwrap(fold.getAttribute('data-extra')), + html: true, + placement: 'top', + template: + '', + }) + .on('show.bs.popover', () => { + this.tooltipOpen = true; + }) + .on('hide.bs.popover', () => { + this.tooltipOpen = false; + }); + } // So because this is async there's a race condition here if you rapidly switch functions. // This can be triggered by loading an example program. Because the fix going to be tricky I'll defer // to another PR. TODO(jeremy-rifkin) @@ -423,6 +487,7 @@ export class Cfg extends Pane { // display the cfg for the specified function if it exists // this function does not change or use this.state.selectedFunction async selectFunction(name: string | null) { + $('.fold').popover('dispose'); this.blockContainer.innerHTML = ''; this.svg.innerHTML = ''; this.estimatedPNGSize.innerHTML = ''; @@ -548,6 +613,7 @@ export class Cfg extends Pane { const topBarHeight = utils.updateAndCalcTopBarHeight(this.domRoot, this.topBar, this.hideable); this.graphContainer.style.width = `${unwrap(this.domRoot.width())}px`; this.graphContainer.style.height = `${unwrap(this.domRoot.height()) - topBarHeight}px`; + $('.fold').popover('hide'); }); } diff --git a/static/styles/explorer.scss b/static/styles/explorer.scss index 86e4f229742..1c8819b8de3 100644 --- a/static/styles/explorer.scss +++ b/static/styles/explorer.scss @@ -418,11 +418,23 @@ pre.content.wrap * { font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; line-height: 100%; + .fold { + display: inline-block; + color: grey; + margin: 0.1em 0.1em 0 0.2em; + line-height: 1em; + cursor: pointer; + } } } } } +.cfg-fold-popover { + font-family: Consolas, 'Liberation Mono', Courier, monospace; + max-width: calc(min(95vw, 1000px)); +} + .cfg-toolbar { .estimated-export-size { font-size: x-small;