Skip to content

Commit 1ce9547

Browse files
authored
feat: Add clickable links in cell overflow modal (#1147)
Closes #1128 Links without `https` are also recognized as links. I couldn't figure out how to disable the tooltip or open the link upon left click.
1 parent b0865eb commit 1ce9547

7 files changed

Lines changed: 73 additions & 0 deletions

File tree

package-lock.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/console/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"@deephaven/utils": "file:../utils",
3333
"@fortawesome/react-fontawesome": "^0.2.0",
3434
"classnames": "^2.3.1",
35+
"linkifyjs": "^4.1.0",
3536
"lodash.debounce": "^4.0.8",
3637
"lodash.throttle": "^4.1.1",
3738
"memoize-one": "^5.1.1",

packages/console/src/monaco/MonacoTheme.module.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,9 @@
6565
editor-suggest-widget-selected-background: mix($primary, $gray-700, 15%);
6666
editor-suggest-widget-highlightForeground: $primary;
6767
list-hover-background: $gray-600;
68+
69+
// links
70+
text-link-foreground: $link-color;
71+
text-link-active-foreground: $link-hover-color;
72+
editor-link-active-foreground: $link-hover-color;
6873
}

packages/console/src/monaco/MonacoUtils.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,30 @@ describe('Mac shortcuts', () => {
150150
);
151151
});
152152
});
153+
154+
describe('provideLinks', () => {
155+
it('it should get a provideLinks function which should return an object with the links', () => {
156+
const { provideLinks } = MonacoUtils;
157+
const mockModel: monaco.editor.ITextModel = ({
158+
getLineCount: jest.fn(() => 2),
159+
getLineContent: jest.fn(lineNumber =>
160+
lineNumber === 1
161+
? 'google.com http://www.example.com/'
162+
: 'mail@gmail.com'
163+
),
164+
} as unknown) as monaco.editor.ITextModel;
165+
166+
const expectedValue = {
167+
links: [
168+
{ url: 'http://google.com', range: new monaco.Range(1, 1, 1, 11) },
169+
{
170+
url: 'http://www.example.com/',
171+
range: new monaco.Range(1, 12, 1, 35),
172+
},
173+
{ url: 'mailto:mail@gmail.com', range: new monaco.Range(2, 1, 2, 15) },
174+
],
175+
};
176+
177+
expect(provideLinks(mockModel)).toEqual(expectedValue);
178+
});
179+
});

packages/console/src/monaco/MonacoUtils.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import { Shortcut } from '@deephaven/components';
66
import { IdeSession } from '@deephaven/jsapi-shim';
77
import { assertNotNull } from '@deephaven/utils';
8+
import { find as linkifyFind } from 'linkifyjs';
89
import * as monaco from 'monaco-editor';
910
import type { Environment } from 'monaco-editor';
1011
// @ts-ignore
@@ -140,6 +141,10 @@ class MonacoUtils {
140141
'input.background': MonacoTheme['input-background'],
141142
'input.foreground': MonacoTheme['input-foreground'],
142143
'input.border': MonacoTheme['input-border'],
144+
'textLink.foreground': MonacoTheme['text-link-foreground'],
145+
'textLink.activeForeground': MonacoTheme['text-link-active-foreground'],
146+
'editorLink.activeForeground':
147+
MonacoTheme['editor-link-active-foreground'],
143148
};
144149

145150
monaco.editor.defineTheme('dh-dark', {
@@ -450,6 +455,28 @@ class MonacoUtils {
450455
KeyCodeUtils.fromString(keyValue)
451456
);
452457
}
458+
459+
static provideLinks(
460+
model: monaco.editor.ITextModel
461+
): { links: monaco.languages.ILink[] } {
462+
const newTokens: monaco.languages.ILink[] = [];
463+
464+
for (let i = 1; i <= model.getLineCount(); i += 1) {
465+
const lineText = model.getLineContent(i);
466+
const tokens = linkifyFind(lineText);
467+
// map the tokens to the ranges - you know the line number now, use the token start/end as the startColumn/endColumn
468+
tokens.forEach(token => {
469+
newTokens.push({
470+
url: token.href,
471+
range: new monaco.Range(i, token.start + 1, i, token.end + 1),
472+
});
473+
});
474+
}
475+
476+
return {
477+
links: newTokens,
478+
};
479+
}
453480
}
454481

455482
export default MonacoUtils;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import '@deephaven/components/scss/custom.scss';
2+
3+
.monaco-editor .detected-link {
4+
color: $link-color;
5+
}

packages/console/src/notebook/Editor.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import classNames from 'classnames';
66
import * as monaco from 'monaco-editor';
77
import { assertNotNull } from '@deephaven/utils';
88
import MonacoUtils from '../monaco/MonacoUtils';
9+
import './Editor.scss';
910

1011
interface EditorProps {
1112
className: string;
@@ -89,6 +90,7 @@ class Editor extends Component<EditorProps, Record<string, never>> {
8990
tabCompletion: 'on',
9091
value: '',
9192
wordWrap: 'off',
93+
links: true,
9294
...settings,
9395
};
9496
assertNotNull(this.container);
@@ -112,6 +114,10 @@ class Editor extends Component<EditorProps, Record<string, never>> {
112114
this.editor.layout();
113115
MonacoUtils.removeConflictingKeybindings(this.editor);
114116

117+
monaco.languages.registerLinkProvider('plaintext', {
118+
provideLinks: MonacoUtils.provideLinks,
119+
});
120+
115121
onEditorInitialized(this.editor);
116122
}
117123

0 commit comments

Comments
 (0)