Skip to content

Commit 03fa787

Browse files
committed
feat(floating-peek): show line and range memos with hover in floating peek windows
1 parent 2bf0fb6 commit 03fa787

1 file changed

Lines changed: 70 additions & 1 deletion

File tree

static/js/floating-peek.js

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,67 @@
44
// initFloatingPeek(getHoverCtx) を ensureEditor() から呼ぶこと。
55
// getHoverCtx: () => { word: string, hit: {file,line}|null }
66

7+
// フローティングピークのエディタに行メモ・範囲メモのデコレーションを適用する
8+
// lineOffset = file上の行番号 - Monaco上の行番号 (Monaco line 1 = file line lineOffset+1)
9+
function _applyFloatMemoDecos(ed, file, lineOffset) {
10+
const model = ed.getModel();
11+
const normFile = file.replace(/\\/g, '/');
12+
const decos = [];
13+
14+
// 行メモ: デコレーション + hoverProvider用マップを同時構築
15+
const memosByEdLine = {};
16+
Object.entries(getLineMemos()).forEach(([key, memo]) => {
17+
const normKey = key.replace(/\\/g, '/');
18+
if (!normKey.startsWith(normFile + '::')) return;
19+
const edLine = parseInt(normKey.split('::')[1]) - lineOffset;
20+
if (edLine < 1 || edLine > model.getLineCount()) return;
21+
memosByEdLine[edLine] = memo;
22+
decos.push({
23+
range: new monaco.Range(edLine, 1, edLine, 1),
24+
options: {
25+
isWholeLine: true,
26+
glyphMarginClassName: 'line-memo-glyph',
27+
glyphMarginHoverMessage: { value: '✎ ' + memo.split('\n').join('\n\n') },
28+
}
29+
});
30+
});
31+
32+
// 範囲メモ: デコレーション + hoverProvider用リストを同時構築
33+
const rangeMemoList = [];
34+
getRangeMemos().filter(m => m.file.replace(/\\/g,'/') === normFile).forEach(m => {
35+
const edStart = m.startLine - lineOffset;
36+
const edEnd = m.endLine - lineOffset;
37+
if (edEnd < 1 || edStart > model.getLineCount()) return;
38+
rangeMemoList.push({ ...m, edStart, edEnd });
39+
decos.push({
40+
range: new monaco.Range(
41+
Math.max(1, edStart), m.startCol,
42+
Math.min(model.getLineCount(), edEnd), m.endCol
43+
),
44+
options: { className: 'range-memo-highlight' }
45+
});
46+
});
47+
48+
if (decos.length) ed.deltaDecorations([], decos);
49+
if (!Object.keys(memosByEdLine).length && !rangeMemoList.length) return;
50+
51+
// hoverProviderでメモをホバーの先頭に表示(同期的に返すことで言語プロバイダーより先に表示される)
52+
monaco.languages.registerHoverProvider(ed.getModel()?.getLanguageId() || 'plaintext', {
53+
provideHover(_model, position) {
54+
if (_model !== ed.getModel()) return null;
55+
const line = position.lineNumber, col = position.column;
56+
const rangeParts = rangeMemoList.filter(m =>
57+
(line > m.edStart || (line === m.edStart && col >= m.startCol)) &&
58+
(line < m.edEnd || (line === m.edEnd && col <= m.endCol))
59+
).map(m => ({ value: '✎ ' + m.memo.split('\n').join(' \n') }));
60+
if (rangeParts.length) return { contents: rangeParts };
61+
const lm = memosByEdLine[line];
62+
if (lm) return { contents: [{ value: '✎ ' + lm.split('\n').join(' \n') }] };
63+
return null;
64+
}
65+
});
66+
}
67+
768
function initFloatingPeek(getHoverCtx) {
869

970
const _floatingWins = new Map(); // word → DOM element
@@ -378,6 +439,8 @@ function initFloatingPeek(getHoverCtx) {
378439
lineNumbersMinChars: 4,
379440
contextmenu: false,
380441
automaticLayout: true,
442+
glyphMargin: true,
443+
hover: { enabled: true },
381444
});
382445
// enum_member の場合、対象行をハイライト
383446
if (h.kind === 'enum_member' && h.body) {
@@ -389,6 +452,7 @@ function initFloatingPeek(getHoverCtx) {
389452
options: { isWholeLine: true, className: 'float-peek-target-line' }
390453
}]);
391454
}
455+
_applyFloatMemoDecos(ed, h.file, h.line - 1);
392456
win._floatEditors.push(ed);
393457
_attachEditorCtxMenu(ed, win);
394458
});
@@ -427,8 +491,10 @@ function initFloatingPeek(getHoverCtx) {
427491
lineNumbersMinChars: 4,
428492
contextmenu: false,
429493
automaticLayout: true,
494+
glyphMargin: true,
495+
hover: { enabled: true },
430496
});
431-
497+
_applyFloatMemoDecos(ed, file, startLine - 1);
432498
win._floatEditors.push(ed);
433499
_attachEditorCtxMenu(ed, win);
434500
const origClose = win._floatClose;
@@ -474,6 +540,8 @@ function initFloatingPeek(getHoverCtx) {
474540
lineNumbersMinChars: 4,
475541
contextmenu: false,
476542
automaticLayout: true,
543+
glyphMargin: true,
544+
hover: { enabled: true },
477545
});
478546

479547
// ターゲット行をハイライト
@@ -486,6 +554,7 @@ function initFloatingPeek(getHoverCtx) {
486554
ed.revealLineInCenter(targetIdx + 1);
487555
}
488556

557+
if(lines.length) _applyFloatMemoDecos(ed, file, lines[0].line - 1);
489558
win._floatEditors.push(ed);
490559
_attachEditorCtxMenu(ed, win);
491560
const origClose = win._floatClose;

0 commit comments

Comments
 (0)