diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000000..52a439b526a --- /dev/null +++ b/.nojekyll @@ -0,0 +1 @@ +disable jekyll on gh-pages diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a0fde6367e..30633883248 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.31.2](https://github.com/ajaxorg/ace/compare/v1.31.1...v1.31.2) (2023-11-15) + + +### Bug Fixes + +* inline preview with loading state ([05db94f](https://github.com/ajaxorg/ace/commit/05db94f53774f64318de757347f7217043744fe6)) + ### [1.31.1](https://github.com/ajaxorg/ace/compare/v1.31.0...v1.31.1) (2023-10-30) diff --git a/ace.d.ts b/ace.d.ts index 06df3bcf0b2..6ef41082556 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -1071,6 +1071,7 @@ export namespace Ace { setSelectOnHover?: Boolean; stickySelectionDelay?: Number; ignoreCaption?: Boolean; + showLoadingState?: Boolean; emptyMessage?(prefix: String): String; getPopup(): AcePopup; showPopup(editor: Editor, options: CompletionOptions): void; diff --git a/build b/build index 1ac1817ea10..89f8b8c519e 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 1ac1817ea10659f2301858aabde34dcb17b2e67f +Subproject commit 89f8b8c519e73147bc265a408839892383a742af diff --git a/index.html b/index.html index c4bd4bc9693..6c1f058ff14 100644 --- a/index.html +++ b/index.html @@ -1158,6 +1158,10 @@

Projects Using Ace

AIJS +
  • + + K8Studio +
  • +

    Your Site Here diff --git a/lib/ace/mode/xml/sax.js b/lib/ace/mode/xml/sax.js index c962ab8cb13..227451ee15e 100644 --- a/lib/ace/mode/xml/sax.js +++ b/lib/ace/mode/xml/sax.js @@ -154,7 +154,7 @@ function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){ errorHandler.warning('unclosed xml attribute'); } } - appendElement(el,domBuilder,parseStack); + appendElement(el,domBuilder,parseStack,errorHandler); if(el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed){ @@ -347,7 +347,7 @@ function parseElementStartPart(source,start,el,entityReplacer,errorHandler){ /** * @return end of the elementStartPart(end of elementEndPart for selfClosed el) */ -function appendElement(el,domBuilder,parseStack){ +function appendElement(el,domBuilder,parseStack,errorHandler){ var tagName = el.tagName; var localNSMap = null; var currentNSMap = parseStack[parseStack.length-1].currentNSMap; @@ -405,6 +405,9 @@ function appendElement(el,domBuilder,parseStack){ } //no prefix element has default namespace var ns = el.uri = currentNSMap[prefix || '']; + if (prefix && !ns) { + errorHandler.error('unexpected namespace ' + prefix); + } domBuilder.startElement(ns,localName,tagName,el); //endPrefixMapping and startPrefixMapping have not any help for dom builder //localNSMap = null diff --git a/package.json b/package.json index ac00def565b..4b76db4bdac 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ace-code", "description": "Ajax.org Code Editor is a full featured source code highlighting editor that powers the Cloud9 IDE", - "version": "1.31.1", + "version": "1.31.2", "homepage": "http://github.com/ajaxorg/ace", "engines": { "node": ">= 0.6.0" diff --git a/src/autocomplete.js b/src/autocomplete.js index 3dd1180580b..7a8fc868df4 100644 --- a/src/autocomplete.js +++ b/src/autocomplete.js @@ -64,6 +64,14 @@ class Autocomplete { this.parentNode = null; this.setSelectOnHover = false; + /** + * @property {Boolean} showLoadingState - A boolean indicating whether the loading states of the Autocompletion should be shown to the end-user. If enabled + * it shows a loading indicator on the popup while autocomplete is loading. + * + * Experimental: This visualisation is not yet considered stable and might change in the future. + */ + this.showLoadingState = false; + /** * @property {number} stickySelectionDelay - a numerical value that determines after how many ms the popup selection will become 'sticky'. * Normally, when new elements are added to an open popup, the selection is reset to the first row of the popup. If sticky, the focus will remain @@ -91,16 +99,18 @@ class Autocomplete { var initialPosition = this.completionProvider && this.completionProvider.initialPosition; if (this.autoShown || (this.popup && this.popup.isOpen) || !initialPosition) return; - var completionsForEmpty = [{ - caption: config.nls("Loading..."), - value: "" - }]; - this.completions = new FilteredList(completionsForEmpty); + this.completions = new FilteredList(Autocomplete.completionsForLoading); this.openPopup(this.editor, initialPosition.prefix, false); this.popup.renderer.setStyle("ace_loading", true); }.bind(this), this.stickySelectionDelay); } + static get completionsForLoading() { return [{ + caption: config.nls("Loading..."), + value: "" + }]; + } + $init() { this.popup = new AcePopup(this.parentNode || document.body || document.documentElement); this.popup.on("click", function(e) { @@ -238,7 +248,8 @@ class Autocomplete { this.popup.autoSelect = this.autoSelect; this.popup.setSelectOnHover(this.setSelectOnHover); - var previousSelectedItem = this.popup.data[this.popup.getRow()]; + var oldRow = this.popup.getRow(); + var previousSelectedItem = this.popup.data[oldRow]; this.popup.setData(this.completions.filtered, this.completions.filterText); if (this.editor.textInput.setAriaOptions) { @@ -250,12 +261,17 @@ class Autocomplete { editor.keyBinding.addKeyboardHandler(this.keyboardHandler); - var newRow = this.popup.data.indexOf(previousSelectedItem); - - if (newRow && this.stickySelection) - this.popup.setRow(this.autoSelect ? newRow : -1); - else - this.popup.setRow(this.autoSelect ? 0 : -1); + var newRow; + if (this.stickySelection) + newRow = this.popup.data.indexOf(previousSelectedItem); + if (!newRow || newRow === -1) + newRow = 0; + + this.popup.setRow(this.autoSelect ? newRow : -1); + + // If we stay on the same row, but the content is different, we want to update the popup. + if (newRow === oldRow && previousSelectedItem !== this.completions.filtered[newRow]) + this.$onPopupChange(); if (!keepPopupPosition) { this.popup.setTheme(editor.getTheme()); @@ -458,6 +474,7 @@ class Autocomplete { }]; this.completions = new FilteredList(completionsForEmpty); this.openPopup(this.editor, prefix, keepPopupPosition); + this.popup.renderer.setStyle("ace_loading", false); return; } return this.detach(); @@ -471,13 +488,20 @@ class Autocomplete { if (this.autoInsert && !this.autoShown && filtered.length == 1) return this.insertMatch(filtered[0]); } - this.completions = completions; + // If showLoadingState is true and there is still a completer loading, show 'Loading...' + // in the top row of the completer popup. + this.completions = !finished && this.showLoadingState ? + new FilteredList( + Autocomplete.completionsForLoading.concat(filtered), completions.filterText + ) : + completions; + this.openPopup(this.editor, prefix, keepPopupPosition); this.popup.renderer.setStyle("ace_loading", !finished); }.bind(this)); - if (!this.autoShown && !(this.popup && this.popup.isOpen)) { + if (this.showLoadingState && !this.autoShown && !(this.popup && this.popup.isOpen)) { this.$firstOpenTimer.delay(this.stickySelectionDelay/2); } } diff --git a/src/autocomplete_test.js b/src/autocomplete_test.js index 1f5dded01ba..c16904e24e0 100644 --- a/src/autocomplete_test.js +++ b/src/autocomplete_test.js @@ -989,6 +989,7 @@ module.exports = { var completer = Autocomplete.for(editor); completer.stickySelectionDelay = 100; + completer.showLoadingState = true; user.type("Ctrl-Space"); assert.ok(!(completer.popup && completer.popup.isOpen)); @@ -1005,8 +1006,11 @@ module.exports = { editor.completers = [fastCompleter, slowCompleter]; user.type("Ctrl-Space"); - assert.equal(completer.popup.data.length, 3); + assert.equal(completer.popup.data.length, 4); + + // Should have top row saying 'Loading...' together with results. assert.ok(isLoading()); + assert.equal(completer.popup.data[0].caption, "Loading..."); setTimeout(() => { completer.popup.renderer.$loop._flush(); assert.equal(completer.popup.data.length, 5); @@ -1016,6 +1020,106 @@ module.exports = { }, 150); }, 100); + function isLoading() { + return completer.popup.renderer.container.classList.contains("ace_loading"); + } + }, + "test: should not display loading state on no suggestion state": function(done) { + var editor = initEditor("hello world\n"); + + var slowCompleter = { + getCompletions: function (editor, session, pos, prefix, callback) { + var completions = [ + { + caption: "slow option 1", + value: "s1", + score: 3 + }, { + caption: "slow option 2", + value: "s2", + score: 0 + } + ]; + setTimeout(() => { + callback(null, completions); + }, 200); + } + }; + + editor.completers = [slowCompleter]; + + var completer = Autocomplete.for(editor); + completer.stickySelectionDelay = 100; + completer.emptyMessage = "no completions"; + completer.showLoadingState = true; + + user.type("doesntmatchanything"); + user.type("Ctrl-Space"); + assert.ok(!(completer.popup && completer.popup.isOpen)); + + setTimeout(() => { + completer.popup.renderer.$loop._flush(); + assert.equal(completer.popup.data.length, 1); + assert.ok(isLoading()); + setTimeout(() => { + // Should show no suggestions state without loading indicator + assert.equal(completer.popup.data.length, 1); + assert.equal(completer.popup.data[0].caption, "no completions"); + assert.ok(!isLoading()); + + done(); + }, 150); + }, 100); + + function isLoading() { + return completer.popup.renderer.container.classList.contains("ace_loading"); + } + }, + "test: should display ghost text after loading state if inline preview enabled": function(done) { + var editor = initEditor("hello world\n"); + + var slowCompleter = { + getCompletions: function (editor, session, pos, prefix, callback) { + var completions = [ + { + caption: "slow option 1", + value: "s1", + score: 3 + }, { + caption: "slow option 2", + value: "s2", + score: 0 + } + ]; + setTimeout(() => { + callback(null, completions); + }, 200); + } + }; + + editor.completers = [slowCompleter]; + + var completer = Autocomplete.for(editor); + completer.stickySelectionDelay = 100; + completer.inlineEnabled = true; + completer.showLoadingState = true; + + user.type("Ctrl-Space"); + assert.ok(!(completer.popup && completer.popup.isOpen)); + + setTimeout(() => { + completer.popup.renderer.$loop._flush(); + assert.equal(completer.popup.data.length, 1); + assert.ok(isLoading()); + setTimeout(() => { + assert.equal(completer.popup.data.length, 2); + assert.ok(!isLoading()); + + assert.strictEqual(editor.renderer.$ghostText.text, "s1"); + done(); + }, 150); + }, 100); + function isLoading() { return completer.popup.renderer.container.classList.contains("ace_loading"); } diff --git a/src/config.js b/src/config.js index b71bfc51eb5..67eafa228ca 100644 --- a/src/config.js +++ b/src/config.js @@ -168,6 +168,6 @@ var reportErrorIfPathIsNotConfigured = function() { } }; -exports.version = "1.31.1"; +exports.version = "1.31.2"; diff --git a/src/mode/prql_highlight_rules.js b/src/mode/prql_highlight_rules.js index a30d1ae6717..51ee6b3fd49 100644 --- a/src/mode/prql_highlight_rules.js +++ b/src/mode/prql_highlight_rules.js @@ -22,6 +22,7 @@ var PrqlHighlightRules = function() { "int16", "int32", "int64", + "int128", "float", "text", "set"].join("|"); @@ -35,7 +36,7 @@ var PrqlHighlightRules = function() { "support.type": builtinTypes }, "identifier"); - var escapeRe = /\\(\d+|['"\\&bfnrt]|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{2})/; + var escapeRe = /\\(\d+|['"\\&bfnrt]|u\{[0-9a-fA-F]{1,6}\}|x[0-9a-fA-F]{2})/; var identifierRe = /[A-Za-z_][a-z_A-Z0-9]/.source; var numRe = /(?:\d\d*(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+\b)?/.source; var bidi = "[\\u202A\\u202B\\u202D\\u202E\\u2066\\u2067\\u2068\\u202C\\u2069]";