diff --git a/ace.d.ts b/ace.d.ts index 28c926a0610..b7d483857c7 100644 --- a/ace.d.ts +++ b/ace.d.ts @@ -227,6 +227,7 @@ export namespace Ace { value: string; session: EditSession; relativeLineNumbers: boolean; + enableMultiselect: boolean; enableKeyboardAccessibility: boolean; } @@ -275,17 +276,15 @@ export namespace Ace { type: string; } - export interface TooltipMarker { + export interface MarkerGroupItem { range: Range; - tooltipText: string; - className?: string; - priority?: number; + className: string; } export class MarkerGroup { - constructor(); - setMarkers: (markers: TooltipMarker[]) => void; - getMarkerAtPos: (pos: Position) => TooltipMarker; + constructor(session: EditSession); + setMarkers: (markers: MarkerGroupItem[]) => void; + getMarkerAtPosition: (pos: Position) => MarkerGroupItem; } diff --git a/demo/kitchen-sink/demo.js b/demo/kitchen-sink/demo.js index 35144001b95..ed48cf8e7c6 100644 --- a/demo/kitchen-sink/demo.js +++ b/demo/kitchen-sink/demo.js @@ -46,7 +46,6 @@ var ElasticTabstopsLite = require("ace/ext/elastic_tabstops_lite").ElasticTabsto var IncrementalSearch = require("ace/incremental_search").IncrementalSearch; var TokenTooltip = require("./token_tooltip").TokenTooltip; -var TooltipMarkerManager = require("ace/marker_group").TooltipMarkerManager; require("ace/config").defineOptions(Editor.prototype, "editor", { showTokenInfo: { set: function(val) { @@ -101,18 +100,21 @@ function loadLanguageProvider(editor) { }); window.languageProvider = languageProvider; languageProvider.registerEditor(editor); + // hack to replace tooltip implementation from ace-linters with hover tooltip + // can be removed when ace-linters is updated to use MarkerGroup and HoverTooltip if (languageProvider.$descriptionTooltip) editor.off("mousemove", languageProvider.$descriptionTooltip.onMouseMove); languageProvider.$messageController.$worker.addEventListener("message", function(e) { var id = e.data.sessionId.split(".")[0]; var session = languageProvider.$getSessionLanguageProvider({id: id})?.session; if (e.data.type == 6) { + // annotation message e.stopPropagation(); if (session) { showAnnotations(session, e.data.value); } } else if (e.data.type == 13) { - // ignore signatures + // highlights message if (session) showOccurrenceMarkers(session, e.data.value); } }, true); @@ -124,9 +126,12 @@ function loadLanguageProvider(editor) { var r = el.range; return { range: new Range(r.start.line, r.start.character, r.end.line, r.end.character), - className: el.kind == 3 - ? "language_highlight_occurrence_main" - : "language_highlight_occurrence_other" + // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentHighlightKind + className: el.kind == 2 + ? "language_highlight_read" + : el.kind == 3 + ? "language_highlight_write" + : "language_highlight_text" }; })); } @@ -175,8 +180,8 @@ function loadLanguageProvider(editor) { }; var domNode = dom.buildDom(["div", {}, - hoverNode, - errorMarker && ["div", {}, errorMarker.tooltipText.trim()] + errorMarker && ["div", {}, errorMarker.tooltipText.trim()], + hoverNode ]); docTooltip.showForRange(editor, range, domNode, e); }); diff --git a/demo/kitchen-sink/styles.css b/demo/kitchen-sink/styles.css index d681144bf33..d9c908d1d04 100644 --- a/demo/kitchen-sink/styles.css +++ b/demo/kitchen-sink/styles.css @@ -113,23 +113,14 @@ body { z-index: 2000; border-radius: 0; } -.language_highlight_occurrence_main { +.language_highlight_text, .language_highlight_read, .language_highlight_write { position: absolute; box-sizing: border-box; border: solid 1px #888; z-index: 2000; } -.ace_dark .language_highlight_occurrence_main { - border: solid 1px #888; -} -.language_highlight_occurrence_other { - position: absolute; - box-sizing: border-box; - border: solid 1px #888; - z-index: 2000; -} -.ace_dark .language_highlight_occurrence_other { - border: solid 1px #888; +.language_highlight_write { + border: solid 1px #F88; } .ace_doc-tooltip pre { margin: 0; diff --git a/src/marker_group.js b/src/marker_group.js index 6aac0ec97cc..602e23ba18a 100644 --- a/src/marker_group.js +++ b/src/marker_group.js @@ -14,6 +14,11 @@ class MarkerGroup { session.addDynamicMarker(this); } + /** + * Finds the first marker containing pos + * @param {Position} pos + * @returns MarkerGroupItem + */ getMarkerAtPosition(pos) { return this.markers.find(function(marker) { return marker.range.contains(pos.row, pos.column); @@ -33,7 +38,7 @@ class MarkerGroup { /** * Sets marker definitions to be rendered. Limits the number of markers at MAX_MARKERS. - * @param {Ace.TooltipMarker[]} markers an array of marker definitions. + * @param {Ace.MarkerGroupItem[]} markers an array of marker definitions. */ setMarkers(markers) { this.markers = markers.sort(this.markersComparator).slice(0, this.MAX_MARKERS); @@ -77,7 +82,7 @@ class MarkerGroup { // this caps total amount of markers at 500 - should it maybe be done only for rendered markers? // on top of it, do we need to cap the length of a rendered marker range to avoid performance issues? -MarkerGroup.prototype.MAX_MARKERS = 500; +MarkerGroup.prototype.MAX_MARKERS = 10000; exports.MarkerGroup = MarkerGroup; diff --git a/src/marker_group_test.js b/src/marker_group_test.js index 8015bc5ec59..e619436f754 100644 --- a/src/marker_group_test.js +++ b/src/marker_group_test.js @@ -1,4 +1,3 @@ -/*global CustomEvent*/ if (typeof process !== "undefined") { require("./test/mockdom"); } @@ -6,121 +5,68 @@ if (typeof process !== "undefined") { "use strict"; var ace = require("./ace"); +var dom = require("./lib/dom"); var assert = require("./test/assertions"); var EditSession = require("./edit_session").EditSession; var Range = require("./range").Range; -var TooltipMarkerManager = require("./marker_group").TooltipMarkerManager; -var editor, tooltipMarkerManager; +var MarkerGroup = require("./marker_group").MarkerGroup; +var editor; var session1, session2; module.exports = { setUp: function(next) { - session1 = new EditSession(["Hello empty world", "This is a second line"]); - session2 = new EditSession(["Single line"]); + var value = "Hello empty world\n" + + "This is a second line" + + "\n".repeat(100) + + "line number 100"; + session1 = new EditSession(value); + session2 = new EditSession("2 " + value); editor = ace.edit(null, { session: session1 }); document.body.appendChild(editor.container); editor.container.style.height = "200px"; editor.container.style.width = "300px"; - tooltipMarkerManager = new TooltipMarkerManager(editor); - const singleLineMarker = { - range: new Range(0, 0, 0, 5), - tooltipText: "Single line marker", - className: "ace_tooltip-marker_test", - }; - const multiLineMarker = { - range: new Range(0, 12, 1, 4), - tooltipText: "Multi line marker", - className: "ace_tooltip-marker_test", - }; - - session1.setTooltipMarkers([singleLineMarker, multiLineMarker], tooltipMarkerManager); - - var css = '.ace_tooltip-marker_test { position: absolute; }', - head = document.head || document.getElementsByTagName('head')[0], - style = document.createElement('style'); - head.appendChild(style); - style.appendChild(document.createTextNode(css)); + dom.importCssString('.ace_tooltip-marker_test { position: absolute; }'); next(); }, - "test: show tooltip marker": function(next) { + "test: show markers": function() { editor.resize(true); - tooltipMarkerManager.hoverTooltip.idleTime = 3; - mouse("move", {row: 0, column: 1}); - setTimeout(function() { - var nodes = document.querySelectorAll(".ace_marker-tooltip"); - assert.equal(nodes.length, 1); - assert.equal(nodes[0].textContent, "Single line marker"); - assert.equal(tooltipMarkerManager.hoverTooltip.$element.style.display, "block"); - mouse("move", {row: 0, column: 9}); - setTimeout(function() { - assert.equal(tooltipMarkerManager.hoverTooltip.$element.style.display, "none"); - mouse("move", {row: 0, column: 15}); - setTimeout(function() { - assert.equal(tooltipMarkerManager.hoverTooltip.$element.style.display, "block"); - nodes = document.querySelectorAll(".ace_marker-tooltip"); - assert.equal(nodes.length, 1); - assert.equal(nodes[0].textContent, "Multi line marker"); - mouse("move", {row: 1, column: 1}); - setTimeout(function() { - assert.equal(tooltipMarkerManager.hoverTooltip.$element.style.display, "block"); - nodes = document.querySelectorAll(".ace_marker-tooltip"); - assert.equal(nodes.length, 1); - assert.equal(nodes[0].textContent, "Multi line marker"); - mouse("move", {row: 0, column: 9}); - next(); - }, 6); - }, 6); - }); - }, 6); - }, - "test: don't show tooltip in edit session without markers": function(next) { - editor.resize(true); - tooltipMarkerManager.hoverTooltip.idleTime = 3; - mouse("move", {row: 0, column: 1}); - setTimeout(function() { - var nodes = document.querySelectorAll(".ace_marker-tooltip"); - assert.equal(nodes.length, 1); - assert.equal(nodes[0].textContent, "Single line marker"); - assert.equal(tooltipMarkerManager.hoverTooltip.$element.style.display, "block"); - mouse("move", {row: 0, column: 9}); - editor.setSession(session2); - editor.resize(true); - mouse("move", {row: 0, column: 1}); - setTimeout(function() { - assert.equal(tooltipMarkerManager.hoverTooltip.$element.style.display, "none"); - next(); - }, 6); - }, 6); + editor.renderer.$loop._flush(); + var markerGroup = new MarkerGroup(session1); + + markerGroup.setMarkers([{ + range: new Range(0, 0, 0, 5), + className: "ace_tooltip-marker_test m2" + }, { + range: new Range(0, 12, 1, 4), + className: "ace_tooltip-marker_test m1" + }]); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 2); + assert.equal(editor.container.querySelectorAll(".m2").length, 1); + editor.setSession(session2); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 0); + editor.setSession(session1); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 2); + editor.execCommand("gotoend"); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 0); + editor.execCommand("gotostart"); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 2); + markerGroup.setMarkers([]); + editor.renderer.$loop._flush(); + assert.equal(editor.container.querySelectorAll(".m1").length, 0); }, tearDown: function() { editor.destroy(); - tooltipMarkerManager.destroy(); - editor = tooltipMarkerManager = null; } }; -function mouse(type, pos, properties) { - var target = editor.renderer.getMouseEventTarget(); - var event = new CustomEvent("mouse" + type, {bubbles: true}); - - if ("row" in pos) { - var pagePos = editor.renderer.textToScreenCoordinates(pos.row, pos.column); - event.clientX = pagePos.pageX; - event.clientY = pagePos.pageY; - } else { - target = pos; - var rect = target.getBoundingClientRect(); - event.clientX = rect.left + rect.width / 2; - event.clientY = rect.top + rect.height / 2; - } - Object.assign(event, properties); - target.dispatchEvent(event); -} - - if (typeof module !== "undefined" && module === require.main) { require("asyncjs").test.testcase(module.exports).exec(); } diff --git a/src/test/all_browser.js b/src/test/all_browser.js index b8dbc093dcd..c6143d6ade2 100644 --- a/src/test/all_browser.js +++ b/src/test/all_browser.js @@ -70,7 +70,7 @@ var testNames = [ "ace/search_test", "ace/selection_test", "ace/snippets_test", - "ace/tooltip_marker_test", + "ace/marker_group_test", "ace/tooltip_test", "ace/token_iterator_test", "ace/tokenizer_test",