Search code examples
ace-editor

Empty line in ace editor shows "x" mark in custom mode


I already worked on the following ticket How to integrate syntax check in Ace Editor using custom mode?

I want to build the custom mode for ace editor (i.e every lines must contains semi colon except empty lines), so I created worker and mode based on above ticket, but now the issue is "missing semicolon" error shown for empty lines

consider the example:

  1. In the ace editor, type in a query1, query2 in line 1 and line 2 respectively
  2. Leave the third line blank
  3. Now in fourth line, type a query without semicolon in the end, x mark appears in third line 4 And when the fifth line is also without a semicolon, then the x mark is displayed at fourth query

In the image "X" mark is shown for wrong line, How do I fix it?

enter image description here


Solution

  • To not show error for empty strings you need to continue loop in the case if lastLineCharacter is empty. So instead of

         if (lastLineCharacter === ';')
             continue;
    

    use

         if (!lastLineCharacter || lastLineCharacter === ';')
             continue;
    

    or use a regexp

         if (/[^;\s]\s*$/.test(lines[i]))
             continue;
    

    Here's a complete working example

    define('ace/mode/javascript-custom', [], function(require, exports, module) {
    
      var oop = require("ace/lib/oop");
      var TextMode = require("ace/mode/text").Mode;
      var Tokenizer = require("ace/tokenizer").Tokenizer;
      var ExampleHighlightRules = require("ace/mode/example_highlight_rules").ExampleHighlightRules;
    
      var UIWorkerClient = require("ace/worker/worker_client").UIWorkerClient
    
      var Mode = function() {
        this.HighlightRules = ExampleHighlightRules;
      };
      oop.inherits(Mode, TextMode);
    
      (function() {
        this.lineCommentStart = "--";
        this.blockComment = {
          start: "->",
          end: "<-"
        };
    
    
        this.createWorker = function(session) {
          // use UiWorkerClient for the demo
          var worker = new UIWorkerClient(["ace"], "ace/mode/semicolonlineend_worker",
            "SemicolonLineEndCheckWorker");
          debugger
          worker.attachToDocument(session.getDocument());
    
          worker.on("annotate", function(results) {
            session.setAnnotations(results.data);
          });
    
          worker.on("terminate", function() {
            session.clearAnnotations();
          });
    
          return worker;
        };
    
    
      }).call(Mode.prototype);
    
      exports.Mode = Mode;
    });
    
    define('ace/mode/example_highlight_rules', [], function(require, exports, module) {
      var oop = require("ace/lib/oop");
      var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
    
      var ExampleHighlightRules = function() {
    
        var keywordMapper = this.createKeywordMapper({
          "variable.language": "this",
          "keyword": "one|two",
          "constant.language": "true|false|null"
        }, "text", true);
    
        this.$rules = {
          "start": [{
            token: "comment",
            regex: "->",
            next: [{
              regex: "<-",
              token: "comment",
              next: "start"
            }, {
              defaultToken: "comment"
            }]
          }, {
            regex: "\\w+\\b",
            token: keywordMapper
          }, {
            token: "comment",
            regex: "--.*"
          }, {
            token: "string",
            regex: '"',
            next: [{
              regex: /\\./,
              token: "escape.character"
            }, {
              regex: '"',
              token: "string",
              next: "start"
            }, {
              defaultToken: "string"
            }]
          }, {
            token: "numbers",
            regex: /\d+(?:[.](\d)*)?|[.]\d+/
          }]
        };
        this.normalizeRules()
      };
    
      oop.inherits(ExampleHighlightRules, TextHighlightRules);
    
      exports.ExampleHighlightRules = ExampleHighlightRules;
    
    });
    
    define("ace/mode/semicolonlineend_worker", [], function(require, exports, module) {
      "use strict";
    
      var oop = require("../lib/oop");
      var Mirror = require("../worker/mirror").Mirror;
    
      var SemicolonLineEndCheckWorker = exports.SemicolonLineEndCheckWorker = function(sender) {
        Mirror.call(this, sender);
        this.setTimeout(100);
      };
    
      oop.inherits(SemicolonLineEndCheckWorker, Mirror);
    
      (function() {
    
        this.onUpdate = function() {
          var lines = this.doc.getAllLines();
          var errors = [];
    
          for (var i = 0; i < lines.length; i++) {
            var lastLineCharacter = lines[i].trim().slice(-1);
            if (!lastLineCharacter || lastLineCharacter === ';')
              continue;
    
            errors.push({
              row: i,
              column: lines[i].length - 1,
              text: "Missing semicolon at the end of the line",
              type: "warning",
              raw: "Missing semicolon"
            });
    
          }
    
          this.sender.emit("annotate", errors);
        };
    
      }).call(SemicolonLineEndCheckWorker.prototype);
    
    });
    
    
    var langTools = ace.require("ace/ext/language_tools");
    var editor = ace.edit("editor");
    
    editor.session.setMode("ace/mode/javascript-custom");
    editor.setOptions({
      enableBasicAutocompletion: true,
      enableLiveAutocompletion: true,
      theme: "ace/theme/xcode"
    });
    <script src="https://ajaxorg.github.io/ace-builds/src/ace.js"></script>
    
    <!-- included only for demo -->
    <script src="https://ajaxorg.github.io/ace-builds/src/worker-json.js"></script>
    
    <script src="https://ajaxorg.github.io/ace-builds/src/ext-language_tools.js"></script>
    <div id="editor" style="height: 200px; width: 400px">c d e; g
    </div>
    <div id="commandline" style="position: absolute; bottom: 10px; height: 20px; width: 800px;"></div>