@@ -28,10 +28,10 @@ async function GetTheme(editor, light_theme, dark_theme) {
2828 dark_theme . disabled = false ;
2929 editor . setTheme ( 'ace/theme/monokai' ) ;
3030 }
31- //console.log('当前主题', theme);
31+ // console.log('当前主题', theme);
3232}
3333
34- //修改编辑器主题
34+ // 修改编辑器主题
3535async function SetTheme ( editor , light_theme , dark_theme ) {
3636 let theme = eda . sys_Storage . getExtensionUserConfig ( 'theme' ) ;
3737 if ( theme == 'light' ) {
@@ -50,14 +50,12 @@ async function SetTheme(editor, light_theme, dark_theme) {
5050 await eda . sys_Message . showToastMessage ( '当前主题已切换为' + theme , 'info' , 1 ) ;
5151}
5252
53- //注册ACE补全
53+ // 注册ACE补全
5454function ACE_CodingForEDA ( editor , edcode ) {
5555 const completers = [ ] ;
5656 for ( const e of edcode ) {
5757 // 构建 snippet:方法参数提示
58- const paramPlaceholders = e . parameters
59- . map ( ( p , idx ) => `\${${ idx + 1 } :${ p . name } }` )
60- . join ( ', ' ) ;
58+ const paramPlaceholders = e . parameters . map ( ( p , idx ) => `\${${ idx + 1 } :${ p . name } }` ) . join ( ', ' ) ;
6159 const snippet = e . methodPath + '(' + paramPlaceholders + ')' ;
6260 // 按方法名注册
6361 completers . push ( {
@@ -78,13 +76,12 @@ function ACE_CodingForEDA(editor, edcode) {
7876 }
7977 // 清除旧的 EDA 补全
8078 editor . completers = editor . completers . filter ( ( c ) => {
81- return ! c . getCompletions ||
82- ! ( c . meta === 'method' || c . meta === 'desc' ) ;
79+ return ! c . getCompletions || ! ( c . meta === 'method' || c . meta === 'desc' ) ;
8380 } ) ;
8481 // 注册新的 completer
8582 editor . completers . push ( {
8683 identifierRegexps : [ / [ \w \$ \u00A2 - \uFFFF ] / ] ,
87- getCompletions : function ( editor , session , pos , prefix , callback ) {
84+ getCompletions : function ( editor , session , pos , prefix , callback ) {
8885 const { row, column } = pos ;
8986 const tokens = session . getTokens ( row ) ;
9087 let tokenStart = 0 ;
@@ -108,9 +105,7 @@ function ACE_CodingForEDA(editor, edcode) {
108105 if ( prefix === '' ) {
109106 return callback ( null , [ ] ) ;
110107 }
111- const matches = completers . filter ( ( item ) =>
112- item . caption . toLowerCase ( ) . includes ( prefix . toLowerCase ( ) )
113- ) ;
108+ const matches = completers . filter ( ( item ) => item . caption . toLowerCase ( ) . includes ( prefix . toLowerCase ( ) ) ) ;
114109 callback ( null , matches ) ;
115110 } ,
116111 } ) ;
@@ -121,16 +116,15 @@ function buildDocText(item) {
121116 let doc = item . description + '\n用法:' + item . methodPath + '()\n' ;
122117 if ( item . parameters && item . parameters . length > 0 ) {
123118 doc += '参数:\n' ;
124- item . parameters . forEach ( p => {
119+ item . parameters . forEach ( ( p ) => {
125120 doc += ` • ${ p . name } : ${ p . description } \n` ;
126121 } ) ;
127122 } else {
128- doc += '\n此方法无参数,可直接调用'
123+ doc += '\n此方法无参数,可直接调用' ;
129124 }
130125 return doc . trim ( ) + '\n\n返回值:' + item . returns ;
131126}
132127
133-
134128// 滚动+Ctrl放大或缩小代码
135129function ACE_ChangeCodeSize ( editor , currentFontSize , showToast ) {
136130 editor . container . addEventListener (
@@ -147,7 +141,8 @@ function ACE_ChangeCodeSize(editor, currentFontSize, showToast) {
147141 showToast ( currentFontSize + 'px:' + ( currentFontSize / 14 ) * 100 + '%' ) ;
148142 }
149143 editor . setFontSize ( currentFontSize ) ;
150- } , { passive : false } ,
144+ } ,
145+ { passive : false } ,
151146 ) ;
152147}
153148
@@ -163,7 +158,6 @@ function ACE_RunCode(editor) {
163158 } catch ( error ) {
164159 console . error ( '执行出错:' , error ) ;
165160 }
166-
167161}
168162
169163// ==========================
@@ -237,7 +231,7 @@ function createQuickButton(editor, name, code) {
237231 li . remove ( ) ; // 移除整个 <li>
238232 eda . sys_Message . showToastMessage ( `已删除快捷按钮 "${ name } "` , 'info' , 1 ) ;
239233 } )
240- . catch ( err => {
234+ . catch ( ( err ) => {
241235 console . error ( '删除失败:' , err ) ;
242236 eda . sys_Message . showToastMessage ( `删除失败: ${ err . message } ` , 'error' , 1 ) ;
243237 } ) ;
@@ -258,10 +252,16 @@ async function Code_SaveToBtnList(editor) {
258252 return ;
259253 }
260254
261- eda . sys_Dialog . showInputDialog ( '请输入按钮名称:' , '该名称将作为左侧工具栏的新按钮,不可重复。' , '保存为快捷按钮' , 'text' , '' , {
255+ eda . sys_Dialog . showInputDialog (
256+ '请输入按钮名称:' ,
257+ '该名称将作为左侧工具栏的新按钮,不可重复。' ,
258+ '保存为快捷按钮' ,
259+ 'text' ,
260+ '' ,
261+ {
262262 placeholder : '例如:自动布线脚本' ,
263263 minlength : 1 ,
264- maxlength : 50
264+ maxlength : 50 ,
265265 } ,
266266 async ( inputValue ) => {
267267 if ( inputValue == null || ! inputValue . trim ( ) ) return ;
@@ -273,7 +273,7 @@ async function Code_SaveToBtnList(editor) {
273273 const store = tx . objectStore ( 'BtnList' ) ;
274274
275275 // 检查重名
276- const existing = await new Promise ( res => {
276+ const existing = await new Promise ( ( res ) => {
277277 const req = store . index ( 'name' ) . get ( name ) ;
278278 req . onsuccess = ( ) => res ( ! ! req . result ) ;
279279 } ) ;
@@ -297,7 +297,7 @@ async function Code_SaveToBtnList(editor) {
297297 } catch ( error ) {
298298 eda . sys_Message . showToastMessage ( `保存失败: ${ error . message } ` , 'error' , 2 ) ;
299299 }
300- }
300+ } ,
301301 ) ;
302302}
303303
@@ -317,7 +317,7 @@ async function Code_LoadBtnListFromDB(editor) {
317317 const ul = document . querySelector ( '#sidebar ul' ) ;
318318 if ( ! ul ) return ;
319319
320- records . forEach ( record => {
320+ records . forEach ( ( record ) => {
321321 const li = createQuickButton ( editor , record . name , record . code ) ;
322322 ul . appendChild ( li ) ;
323323 } ) ;
@@ -341,7 +341,7 @@ function ExtStore_Init() {
341341 } ;
342342 request . onsuccess = ( e ) => {
343343 const result = e . target . result ;
344- //console.log('数据库打开成功', result);
344+ // console.log('数据库打开成功', result);
345345 resolve ( result ) ;
346346 } ;
347347 request . onerror = ( e ) => {
@@ -538,8 +538,8 @@ async function showPluginManagerModal(editor) {
538538 border-radius: 4px;
539539 outline: none;
540540 ` ;
541- nameInput . onfocus = ( ) => nameInput . style . borderColor = '#888' ;
542- nameInput . onblur = ( ) => nameInput . style . borderColor = '#666' ;
541+ nameInput . onfocus = ( ) => ( nameInput . style . borderColor = '#888' ) ;
542+ nameInput . onblur = ( ) => ( nameInput . style . borderColor = '#666' ) ;
543543 inputGroup . appendChild ( nameInput ) ;
544544
545545 const saveBtn = document . createElement ( 'button' ) ;
@@ -721,7 +721,7 @@ async function ExtStore_LoadAndRunAllPlugins(globalContext = {}, onLog = (msg, t
721721 try {
722722 // 直接使用 eval 执行插件代码
723723 eval ( record . code ) ;
724- //onLog(`插件 "${record.name}" 执行成功`, 'success');
724+ // onLog(`插件 "${record.name}" 执行成功`, 'success');
725725 results . push ( { name : record . name , status : 'success' } ) ;
726726 } catch ( err ) {
727727 console . error ( `插件 "${ record . name } " 执行出错:` , err ) ;
@@ -732,10 +732,10 @@ async function ExtStore_LoadAndRunAllPlugins(globalContext = {}, onLog = (msg, t
732732 cursor . continue ( ) ;
733733 } else {
734734 // 清理临时挂载的全局变量
735- tempKeys . forEach ( key => {
735+ tempKeys . forEach ( ( key ) => {
736736 delete window [ key ] ;
737737 } ) ;
738- //onLog(`共执行 ${results.length} 个插件`, 'info');
738+ // onLog(`共执行 ${results.length} 个插件`, 'info');
739739 resolve ( results ) ;
740740 }
741741 } ;
@@ -745,7 +745,7 @@ async function ExtStore_LoadAndRunAllPlugins(globalContext = {}, onLog = (msg, t
745745 console . error ( '扫描插件数据库失败:' , error ) ;
746746
747747 // 清理(即使出错也要清理)
748- tempKeys . forEach ( key => {
748+ tempKeys . forEach ( ( key ) => {
749749 delete window [ key ] ;
750750 } ) ;
751751
@@ -796,4 +796,83 @@ function ImportFile(editor) {
796796
797797 // 触发文件选择窗口
798798 input . click ( ) ;
799- }
799+ }
800+
801+ /**
802+ * 注入右键菜单项:「跳转方法文档」
803+ * @param {Object } editor - ACE 编辑器实例
804+ * @param {Array<string> } fullMethodPaths - 完整方法路径列表,如 ['eda.DMT_Board.copyBoard', ...]
805+ */
806+ function injectContextMenuJumpToDocs ( editor , fullMethodPaths ) {
807+ const container = editor . container ;
808+
809+ // 监听标准 contextmenu 事件(右键完整操作后触发)
810+ container . addEventListener ( 'contextmenu' , ( e ) => {
811+ e . preventDefault ( ) ;
812+
813+ const pos = editor . renderer . screenToTextCoordinates ( e . clientX , e . clientY ) ;
814+ editor . selection . moveTo ( pos . row , pos . column ) ;
815+ const lineText = editor . session . getLine ( pos . row ) ;
816+
817+ // 按长度降序匹配
818+ const sortedMethods = [ ...fullMethodPaths ] . sort ( ( a , b ) => b . length - a . length ) ;
819+ let matchedMethod = null ;
820+ for ( const method of sortedMethods ) {
821+ const escaped = method . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) ;
822+ const regex = new RegExp ( `\\b${ escaped } \\b` ) ;
823+ if ( regex . test ( lineText ) ) {
824+ matchedMethod = method ;
825+ break ;
826+ }
827+ }
828+
829+ // 创建菜单
830+ const menu = document . createElement ( 'div' ) ;
831+ menu . style . cssText = `
832+ position: fixed;
833+ top: ${ e . clientY } px;
834+ left: ${ e . clientX } px;
835+ background: #2d2d2d;
836+ color: #f8f8f2;
837+ border: 1px solid #555;
838+ border-radius: 4px;
839+ z-index: 100000;
840+ font-size: 13px;
841+ min-width: 160px;
842+ box-shadow: 0 2px 8px rgba(0,0,0,0.4);
843+ user-select: none;
844+ ` ;
845+
846+ const item = document . createElement ( 'div' ) ;
847+ item . textContent = matchedMethod ? '跳转方法文档' : '未找到可跳转的方法' ;
848+ item . style . padding = '6px 12px' ;
849+ item . style . cursor = matchedMethod ? 'pointer' : 'default' ;
850+ item . style . opacity = matchedMethod ? '1' : '0.6' ;
851+
852+ if ( matchedMethod ) {
853+ item . onmouseenter = ( ) => ( item . style . background = '#3a3a3a' ) ;
854+ item . onmouseleave = ( ) => ( item . style . background = '' ) ;
855+ item . onclick = ( ) => {
856+ let clean = matchedMethod . startsWith ( 'eda.' ) ? matchedMethod . substring ( 4 ) : matchedMethod ;
857+ const url = `https://prodocs.lceda.cn/cn/api/reference/pro-api.${ clean . toLowerCase ( ) } .html` ;
858+ window . open ( url , '_blank' ) ;
859+ closeMenu ( ) ;
860+ } ;
861+ }
862+
863+ menu . appendChild ( item ) ;
864+ document . body . appendChild ( menu ) ;
865+
866+ // 关闭菜单函数
867+ function closeMenu ( ) {
868+ if ( menu . parentNode ) menu . parentNode . removeChild ( menu ) ;
869+ document . removeEventListener ( 'click' , closeMenu ) ;
870+ document . removeEventListener ( 'contextmenu' , closeMenu ) ;
871+ }
872+ // 点击任意地方关闭
873+ setTimeout ( ( ) => {
874+ document . addEventListener ( 'click' , closeMenu ) ;
875+ document . addEventListener ( 'contextmenu' , closeMenu ) ;
876+ } , 10 ) ;
877+ } ) ;
878+ }
0 commit comments