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+
768function 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