diff --git a/src/ext/diff/base_diff_view.js b/src/ext/diff/base_diff_view.js index ad0dd01f8e9..21d6107b8ab 100644 --- a/src/ext/diff/base_diff_view.js +++ b/src/ext/diff/base_diff_view.js @@ -57,8 +57,8 @@ class BaseDiffView { this.$syncSelections = false; this.$foldUnchangedOnInput = false; - this.markerB = new DiffHighlight(this, 1); this.markerA = new DiffHighlight(this, -1); + this.markerB = new DiffHighlight(this, 1); } /** @@ -355,34 +355,21 @@ class BaseDiffView { } syncSelect(selection) { - if (this.$updatingSelection) return; - var isOld = selection.session === this.sessionA; + var isSessionA = selection.session === this.diffSession.sessionA; var selectionRange = selection.getRange(); - var currSelectionRange = isOld ? this.selectionRangeA : this.selectionRangeB; - if (currSelectionRange && selectionRange.isEqual(currSelectionRange)) + var currSelectionRange = isSessionA ? this.selectionRangeA : this.selectionRangeB; + if (currSelectionRange && selectionRange.isEqual(currSelectionRange)) { return; - - if (isOld) { - this.selectionRangeA = selectionRange; - } else { - this.selectionRangeB = selectionRange; } - this.$updatingSelection = true; - var newRange = this.transformRange(selectionRange, isOld); + var newRange = this.transformRange(selectionRange, isSessionA); + [this.selectionRangeA, this.selectionRangeB] = isSessionA + ? [selectionRange, newRange] + : [newRange, selectionRange]; if (this.$syncSelections) { - (isOld ? this.editorB : this.editorA).session.selection.setSelectionRange(newRange); - } - this.$updatingSelection = false; - - if (isOld) { - this.selectionRangeA = selectionRange; - this.selectionRangeB = newRange; - } else { - this.selectionRangeA = newRange; - this.selectionRangeB = selectionRange; + (isSessionA ? this.editorB : this.editorA).session.selection.setSelectionRange(newRange); } this.updateSelectionMarker(this.syncSelectionMarkerA, this.sessionA, this.selectionRangeA); @@ -443,8 +430,8 @@ class BaseDiffView { } } } - - scheduleRealign() { + + scheduleRealign() { if (!this.realignPending) { this.realignPending = true; this.editorA.renderer.on("beforeRender", this.realign); @@ -738,7 +725,7 @@ config.defineOptions(BaseDiffView.prototype, "DiffView", { maxDiffs: { value: 5000, }, -}); +}); var emptyGutterRenderer = { getText: function name(params) { diff --git a/src/ext/diff/diff_test.js b/src/ext/diff/diff_test.js index 9f95a870cc5..f5cc61c5b1b 100644 --- a/src/ext/diff/diff_test.js +++ b/src/ext/diff/diff_test.js @@ -313,6 +313,33 @@ module.exports = { assert.equal(editorB.getOption("showFoldWidgets"), true); assert.ok(!editorB.renderer.$gutterLayer.$renderer); }, + "test: column selection": function() { + var diffProvider = new DiffProvider(); + + editorA.session.setValue(getValueA(simpleDiff)); + editorB.session.setValue(getValueB(simpleDiff)); + + diffView = new DiffView({ + editorA, editorB, + diffProvider, + }); + + function getColumnSyncSelectionMarker(editor) { + return Object.values(editor.session.$frontMarkers).filter(function(i) { + return i.clazz === "ace_diff double-triangle"; + })[0]; + } + + var syncSelectionMarkerB = getColumnSyncSelectionMarker(editorB); + + editorA.execCommand("selectdown"); + editorA.execCommand("selectright"); + editorA.renderer.$loop._flush(); + editorB.renderer.$loop._flush(); + + assert.jsonEquals(syncSelectionMarkerB.range.start, {row: 0, column: 0}); + assert.jsonEquals(syncSelectionMarkerB.range.end, {row: 1, column: 2}); + }, }; diff --git a/src/ext/diff/diff_view.js b/src/ext/diff/diff_view.js index f41c80393a1..179517f28af 100644 --- a/src/ext/diff/diff_view.js +++ b/src/ext/diff/diff_view.js @@ -4,6 +4,7 @@ var LineWidgets = require("../../line_widgets").LineWidgets; var BaseDiffView = require("./base_diff_view").BaseDiffView; var config = require("../../config"); +var Range = require("../../range").Range; class DiffView extends BaseDiffView { /** @@ -147,6 +148,38 @@ class DiffView extends BaseDiffView { } } + initSelectionMarkers() { + super.initSelectionMarkers(); + + this.syncSelectionColumnMarkerA = new SyncSelectionColumnMarker(); + this.syncSelectionColumnMarkerB = new SyncSelectionColumnMarker(); + this.sessionA.addDynamicMarker(this.syncSelectionColumnMarkerA, true); + this.sessionB.addDynamicMarker(this.syncSelectionColumnMarkerB, true); + } + clearSelectionMarkers() { + super.clearSelectionMarkers(); + + this.sessionA.removeMarker(this.syncSelectionColumnMarkerA.id); + this.sessionB.removeMarker(this.syncSelectionColumnMarkerB.id); + } + + syncSelect(selection) { + super.syncSelect(selection); + + let isSessionA = selection.session === this.diffSession.sessionA; + + let columnSelectionRangeA, columnSelectionRangeB; + + if (!this.$syncSelections) { + isSessionA + ? columnSelectionRangeB = this.selectionRangeB + : columnSelectionRangeA = this.selectionRangeA; + } + + this.updateSelectionMarker(this.syncSelectionColumnMarkerA, this.diffSession.sessionA, columnSelectionRangeA); + this.updateSelectionMarker(this.syncSelectionColumnMarkerB, this.diffSession.sessionB, columnSelectionRangeB); + } + $attachSessionsEventHandlers() { this.$attachSessionEventHandlers(this.editorA, this.markerA); this.$attachSessionEventHandlers(this.editorB, this.markerB); @@ -207,5 +240,30 @@ class DiffView extends BaseDiffView { } } +class SyncSelectionColumnMarker { + constructor() { + /**@type{number}*/this.id; + this.type = ""; + this.clazz = "ace_diff double-triangle"; + } + + update(html, markerLayer, session, config) { + } + + /** + * @param {Range} range + */ + setRange(range) {//TODO + if (!range) { + this.range = null; + return; + } + let newRange = range.clone(); + newRange.end.column++; + + this.range = newRange; + } +} + exports.DiffView = DiffView; diff --git a/src/ext/diff/styles-css.js b/src/ext/diff/styles-css.js index 466de654367..21c8c7a5d84 100644 --- a/src/ext/diff/styles-css.js +++ b/src/ext/diff/styles-css.js @@ -52,6 +52,28 @@ exports.cssText = ` background: transparent; } +.ace_diff.double-triangle::before, +.ace_diff.double-triangle::after { + content: ""; + position: absolute; +} + +.ace_diff.double-triangle.ace_start::before { + left: 0; + border: solid black 3px; + border-bottom-color: transparent; + border-right-color: transparent; +} + +.ace_diff.double-triangle.ace_end::after { + right: 0; + bottom: 0; + border: solid black 3px; + border-top-color: transparent; + border-left-color: transparent; +} + + /* * Dark Colors */ diff --git a/src/layer/marker.js b/src/layer/marker.js index 3307c7b89b9..d1f3265a55c 100644 --- a/src/layer/marker.js +++ b/src/layer/marker.js @@ -92,7 +92,7 @@ class Marker { else this.drawMultiLineMarker(html, range, marker.clazz, config); } else { - this.drawSingleLineMarker(html, range, marker.clazz + " ace_start" + " ace_br15", config); + this.drawSingleLineMarker(html, range, marker.clazz + " ace_start ace_end" + " ace_br15", config); } } if (this.i !=-1) { @@ -135,7 +135,7 @@ class Marker { curr = next; next = row + 1 < end ? session.getScreenLastRowColumn(row + 1) : row == end ? 0 : range.end.column; this.drawSingleLineMarker(stringBuilder, lineRange, - clazz + (row == start ? " ace_start" : "") + " ace_br" + clazz + (row == start ? " ace_start" : row == end ? " ace_end" : "") + " ace_br" + getBorderClass(row == start || row == start + 1 && range.start.column, prev < curr, curr > next, row == end), layerConfig, row == end ? 0 : 1, extraStyle); } @@ -179,7 +179,7 @@ class Marker { var width = range.end.column * config.characterWidth; this.elt( - clazz + " ace_br12", + clazz + " ace_br12 ace_end", "height:"+ height+ "px;"+ "width:"+ width+ "px;"+ "top:"+ top+ "px;"+ diff --git a/types/ace-ext.d.ts b/types/ace-ext.d.ts index c190183b2f1..b1cdb320e5e 100644 --- a/types/ace-ext.d.ts +++ b/types/ace-ext.d.ts @@ -645,7 +645,7 @@ declare module "ace-code/src/ext/whitespace" { export type EditSession = import("ace-code/src/edit_session").EditSession; } declare module "ace-code/src/ext/diff/styles-css" { - export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #eaffea; /*rgb(74 251 74 / 12%); */\n}\n.ace_diff.delete {\n background-color: #ffecec; /*rgb(251 74 74 / 12%);*/\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n #FFFFFF 5px,\n #FFFFFF 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.8);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.8);\n width: 2px !important;\n}\n\n.ace_diff.selection {\n border-bottom: 1px solid black;\n border-top: 1px solid black;\n background: transparent;\n}\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert.inline {\n background-color: rgba(0, 130, 58, 0.45);\n}\n.ace_dark .ace_diff.delete.inline {\n background-color: rgba(169, 46, 33, 0.55);\n}\n\n.ace_dark .ace_diff.selection {\n border-bottom: 1px solid white;\n border-top: 1px solid white;\n background: transparent;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell {\n background-color: #f0f0f0;\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #eaffea;\n border-left: 3px solid #00FF00;\n padding-left: 0;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #ffecec;\n border-left: 3px solid #FF0000;\n padding-left: 0;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover .mini-diff-added:after {\n display: none;\n}\n.ace_fade-fold-widgets:hover .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n"; + export const cssText: "\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #eaffea; /*rgb(74 251 74 / 12%); */\n}\n.ace_diff.delete {\n background-color: #ffecec; /*rgb(251 74 74 / 12%);*/\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n #FFFFFF 5px,\n #FFFFFF 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.8);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.8);\n width: 2px !important;\n}\n\n.ace_diff.selection {\n border-bottom: 1px solid black;\n border-top: 1px solid black;\n background: transparent;\n}\n\n.ace_diff.double-triangle::before,\n.ace_diff.double-triangle::after {\n content: \"\";\n position: absolute;\n}\n\n.ace_diff.double-triangle.ace_start::before {\n left: 0;\n border: solid black 3px;\n border-bottom-color: transparent;\n border-right-color: transparent;\n}\n\n.ace_diff.double-triangle.ace_end::after {\n right: 0;\n bottom: 0;\n border: solid black 3px;\n border-top-color: transparent;\n border-left-color: transparent;\n}\n\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert.inline {\n background-color: rgba(0, 130, 58, 0.45);\n}\n.ace_dark .ace_diff.delete.inline {\n background-color: rgba(169, 46, 33, 0.55);\n}\n\n.ace_dark .ace_diff.selection {\n border-bottom: 1px solid white;\n border-top: 1px solid white;\n background: transparent;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell,\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell_svg-icons {\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter_other > .ace_gutter-cell,\n.ace_mini-diff_gutter_other > .ace_gutter-cell_svg-icons {\n display: none;\n}\n\n.ace_mini-diff_gutter_other {\n pointer-events: none;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #eaffea;\n border-left: 3px solid #00FF00;\n padding-left: 16px;\n display: block;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #ffecec;\n border-left: 3px solid #FF0000;\n padding-left: 16px;\n display: block;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: \"+\";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: \"-\";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover .mini-diff-added:after {\n display: none;\n}\n.ace_fade-fold-widgets:hover .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n"; } declare module "ace-code/src/ext/diff/gutter_decorator" { export class MinimalGutterDiffDecorator { @@ -699,8 +699,8 @@ declare module "ace-code/src/ext/diff/base_diff_view" { compute: (val1: any, val2: any, options: any) => any[]; }; container: HTMLElement; - markerB: DiffHighlight; markerA: DiffHighlight; + markerB: DiffHighlight; showSideA: boolean; savedOptionsA: Partial; savedOptionsB: Partial; @@ -823,8 +823,19 @@ declare module "ace-code/src/ext/diff/diff_view" { scrollB: any; scrollSetBy: any; scrollSetAt: number; + syncSelectionColumnMarkerA: SyncSelectionColumnMarker; + syncSelectionColumnMarkerB: SyncSelectionColumnMarker; } import { BaseDiffView } from "ace-code/src/ext/diff/base_diff_view"; + class SyncSelectionColumnMarker { + id: number; + type: string; + clazz: string; + update(html: any, markerLayer: any, session: any, config: any): void; + setRange(range: Range): void; + range: Range; + } + import { Range } from "ace-code/src/range"; } declare module "ace-code/src/ext/diff/inline_diff_view" { export class InlineDiffView extends BaseDiffView {