确定 JavaScript 语法在 ACE 的更改处理程序中是不是有效

Posted

技术标签:

【中文标题】确定 JavaScript 语法在 ACE 的更改处理程序中是不是有效【英文标题】:Determine if JavaScript syntax is valid in change handler of ACE确定 JavaScript 语法在 ACE 的更改处理程序中是否有效 【发布时间】:2012-03-19 08:29:53 【问题描述】:

我正在使用 ACE 编辑器进行交互式 javascript 编辑。当我将编辑器设置为 JavaScript 模式时,ACE 会自动确定代码是否有效,如果不是,则会突出显示错误消息和行号。

change 事件处理程序期间,我想在我尝试eval() 之前检测ACE 是否认为代码有效。我认为我可能会这样做的唯一方法是:

var jsMode = require("ace/mode/javascript").Mode;
var editor = ace.edit('mycode'), edEl = document.querySelector('#mycode');
editor.getSession().setMode(new jsMode);
editor.getSession().on('change',function()
  // bail out if ACE thinks there's an error
  if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return;
  try
    eval(editor.getSession().getValue());
  catch(e)
);

但是:

    依靠 UI 中具有特定类的元素的存在似乎非常脆弱,但更重要的是, 在change 回调发生之后进行解析的视觉更新。

因此,我实际上必须等待超过 500 毫秒(JavaScript 工作者启动之前的延迟):

editor.getSession().on('change',function()
  setTimeout(function()
    // bail out if ACE thinks there's an error
    if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return;
    try
      eval(editor.getSession().getValue());
    catch(e)
  ,550); // Must be longer than timeout delay in javascript_worker.js
);

有没有更好的方法,在 JS 模式的一个未记录的 API 中,询问是否有任何错误?

【问题讨论】:

我对 ACE 了解不多,但您能解释一下为什么要使用 eval 吗? @hradac 比这更好,I'll show you(正在进行中)工作。 我正在做类似的事情,也希望得到答案。 eval 每次运行都太昂贵了。 【参考方案1】:

当前会话在注解更改时触发 onChangeAnnotation 事件。

之后,新的一组注解可以按如下方式检索

var annotations = editor.getSession().getAnnotations();

似乎可以解决问题。它返回一个 JSON 对象,其中 row 作为 key,一个数组作为 valuevalue 数组可能有多个对象,具体取决于每一行是否有多个注解。

结构如下(抄自firebug——我写的一个测试脚本)

// annotations would look like
(

82:[
    /*annotation*/
        row:82, 
        column:22, 
        text:"Use the array literal notation [].", 
        type:"warning", 
        lint:/*raw output from jslint*/
    
],

rownumber : [ anotation1, annotation2 ],

...

);

所以..

editor.getSession().on("changeAnnotation", function()

    var annot = editor.getSession().getAnnotations();

    for (var key in annot)
        if (annot.hasOwnProperty(key))
            console.log("[" + annot[key][0].row + " , " + annot[key][0].column + "] - \t" + annot[key][0].text);
    

);

// thanks http://***.com/a/684692/1405348 for annot.hasOwnProperty(key) :)

当注释发生变化时,应该给你当前 Ace 编辑会话中所有注释的列表!

希望这会有所帮助!

【讨论】:

这是很好的信息,但它无助于立即发现问题:注释(包括错误)在编辑器的change 回调中不可用;您必须等到异步验证发生。 编辑了答案!希望现在有帮助! getAnnotations() 格式发生了变化……它现在是一个对象数组。 应该是annot[key].row,而不是annot[key][0].row @OnurYILDIRIM Annotations 对象的每一行都有一个数组“rownumber : [ annotation1, annotation2 ]”;见上文。因为每行可以有多个注释。 (或者现在 API 是否发生了变化?) 编辑:我没有在上面看到 DrFriedParts 的评论。我会检查并纠正它。【参考方案2】:

我找到了一个可能比遍历 DOM 更快的解决方案。编辑器的会话有一个可以使用的 getAnnotations 方法。每个注释都有一个类型,显示它们是否是错误。

这是我为 on 'change' 设置回调的方式

function callback() 
    var annotation_lists = window.aceEditor.getSession().getAnnotations();
    var has_error = false;

    // Unfortunately, you get back a list of lists. However, the first list is
    //   always length one (but not always index 0)
    go_through:
    for (var l in annotation_lists) 
        for (var a in annotation_lists[l]) 
            var annotation = annotation_lists[l][a];
            console.log(annotation.type);
            if (annotation.type === "error") 
                has_error = true;
                break go_through;
            
        
    

    if (!has_error) 
        try 
            eval(yourCodeFromTextBox);
            prevCode = yourCodeFromTextBox;
        
        catch (error) 
            eval(prevCode);
        
    

据我所知,还有两种其他类型的注释:“警告”和“信息”,以防万一您也想检查它们。

我跟踪了在全局(当然,在回调函数范围之外)工作的先前代码,因为代码中经常会出现错误,但注释列表中不会出现错误。在这种情况下,当 eval'ing 错误代码时,它将是 code 并 eval 旧代码。

虽然看起来两个 eval 会慢一些,但在我看来,性能并没有那么糟糕,到目前为止。

【讨论】:

【参考方案3】:

Ace 在内部使用JsHint(在worker 中),正如您在文件中看到的那样,发出了一个事件:

this.sender.emit("jslint", lint.errors);

你可以subscribe这个事件,或者在需要的时候自己调用JSHint代码(很短)。

【讨论】:

订阅该事件听起来是个好主意,这样我就不会为每次编辑解析两次,还因为require("../narcissus/jsparse") 为我返回了null。关于该会话发出什么对象的任何想法?编辑?会议?使用显示如何订阅的代码编辑您的答案肯定会赢得您的接受。 :) 关于注册什么有什么建议吗?【参考方案4】:

我发现您可以在 Ace 1.1.7 中订阅工作人员事件:

对于 javascript 代码,订阅 'jslint' 事件:

session.setMode('ace/mode/javascript');
session.on('changeMode', function() 
  if (session.$worker) 
    session.$worker.on('jslint', function(lint) 
      var messages = lint.data, types;
      if (!messages.length) return ok();
      types = messages.map(function(item) 
        return item.type;
      );
      types.indexOf('error') !== -1 ? ko() : ok();
    );
  
);

对于 JSON 代码,订阅 'error' 和 'ok' 事件:

session.setMode('ace/mode/json');
session.on('changeMode', function() 

  // session.$worker is available when 'changeMode' event triggered
  // You could subscribe worker events here, whatever changes to the
  // content will trigger 'error' or 'ok' events.

  session.$worker.on('error', ko);
  session.$worker.on('ok', ok);
);

【讨论】:

在最近的版本中,事件已重命名:error => annotate / ok => terminate

以上是关于确定 JavaScript 语法在 ACE 的更改处理程序中是不是有效的主要内容,如果未能解决你的问题,请参考以下文章

如何使用自定义模式在 Ace Editor 中集成语法检查?

前端代码编辑器ace 语法验证

如何使用 UndoManager 确定文档是不是有未保存的更改

web端代码文本编辑器ACE

Ace-Editor JSON 自动格式/缩进

ACE Editor 常用Api