feat: 添加vscode编辑器
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,169 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from '../../../base/common/assert.js';
|
||||
import { Emitter } from '../../../base/common/event.js';
|
||||
import { Disposable } from '../../../base/common/lifecycle.js';
|
||||
import * as objects from '../../../base/common/objects.js';
|
||||
import { Range } from '../../common/core/range.js';
|
||||
const defaultOptions = {
|
||||
followsCaret: true,
|
||||
ignoreCharChanges: true,
|
||||
alwaysRevealFirst: true
|
||||
};
|
||||
/**
|
||||
* Create a new diff navigator for the provided diff editor.
|
||||
*/
|
||||
export class DiffNavigator extends Disposable {
|
||||
constructor(editor, options = {}) {
|
||||
super();
|
||||
this._onDidUpdate = this._register(new Emitter());
|
||||
this._editor = editor;
|
||||
this._options = objects.mixin(options, defaultOptions, false);
|
||||
this.disposed = false;
|
||||
this.nextIdx = -1;
|
||||
this.ranges = [];
|
||||
this.ignoreSelectionChange = false;
|
||||
this.revealFirst = Boolean(this._options.alwaysRevealFirst);
|
||||
// hook up to diff editor for diff, disposal, and caret move
|
||||
this._register(this._editor.onDidDispose(() => this.dispose()));
|
||||
this._register(this._editor.onDidUpdateDiff(() => this._onDiffUpdated()));
|
||||
if (this._options.followsCaret) {
|
||||
this._register(this._editor.getModifiedEditor().onDidChangeCursorPosition((e) => {
|
||||
if (this.ignoreSelectionChange) {
|
||||
return;
|
||||
}
|
||||
this.nextIdx = -1;
|
||||
}));
|
||||
}
|
||||
if (this._options.alwaysRevealFirst) {
|
||||
this._register(this._editor.getModifiedEditor().onDidChangeModel((e) => {
|
||||
this.revealFirst = true;
|
||||
}));
|
||||
}
|
||||
// init things
|
||||
this._init();
|
||||
}
|
||||
_init() {
|
||||
const changes = this._editor.getLineChanges();
|
||||
if (!changes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_onDiffUpdated() {
|
||||
this._init();
|
||||
this._compute(this._editor.getLineChanges());
|
||||
if (this.revealFirst) {
|
||||
// Only reveal first on first non-null changes
|
||||
if (this._editor.getLineChanges() !== null) {
|
||||
this.revealFirst = false;
|
||||
this.nextIdx = -1;
|
||||
this.next(1 /* ScrollType.Immediate */);
|
||||
}
|
||||
}
|
||||
}
|
||||
_compute(lineChanges) {
|
||||
// new ranges
|
||||
this.ranges = [];
|
||||
if (lineChanges) {
|
||||
// create ranges from changes
|
||||
lineChanges.forEach((lineChange) => {
|
||||
if (!this._options.ignoreCharChanges && lineChange.charChanges) {
|
||||
lineChange.charChanges.forEach((charChange) => {
|
||||
this.ranges.push({
|
||||
rhs: true,
|
||||
range: new Range(charChange.modifiedStartLineNumber, charChange.modifiedStartColumn, charChange.modifiedEndLineNumber, charChange.modifiedEndColumn)
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (lineChange.modifiedEndLineNumber === 0) {
|
||||
// a deletion
|
||||
this.ranges.push({
|
||||
rhs: true,
|
||||
range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedStartLineNumber + 1, 1)
|
||||
});
|
||||
}
|
||||
else {
|
||||
// an insertion or modification
|
||||
this.ranges.push({
|
||||
rhs: true,
|
||||
range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber + 1, 1)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// sort
|
||||
this.ranges.sort((left, right) => Range.compareRangesUsingStarts(left.range, right.range));
|
||||
this._onDidUpdate.fire(this);
|
||||
}
|
||||
_initIdx(fwd) {
|
||||
let found = false;
|
||||
const position = this._editor.getPosition();
|
||||
if (!position) {
|
||||
this.nextIdx = 0;
|
||||
return;
|
||||
}
|
||||
for (let i = 0, len = this.ranges.length; i < len && !found; i++) {
|
||||
const range = this.ranges[i].range;
|
||||
if (position.isBeforeOrEqual(range.getStartPosition())) {
|
||||
this.nextIdx = i + (fwd ? 0 : -1);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// after the last change
|
||||
this.nextIdx = fwd ? 0 : this.ranges.length - 1;
|
||||
}
|
||||
if (this.nextIdx < 0) {
|
||||
this.nextIdx = this.ranges.length - 1;
|
||||
}
|
||||
}
|
||||
_move(fwd, scrollType) {
|
||||
assert.ok(!this.disposed, 'Illegal State - diff navigator has been disposed');
|
||||
if (!this.canNavigate()) {
|
||||
return;
|
||||
}
|
||||
if (this.nextIdx === -1) {
|
||||
this._initIdx(fwd);
|
||||
}
|
||||
else if (fwd) {
|
||||
this.nextIdx += 1;
|
||||
if (this.nextIdx >= this.ranges.length) {
|
||||
this.nextIdx = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.nextIdx -= 1;
|
||||
if (this.nextIdx < 0) {
|
||||
this.nextIdx = this.ranges.length - 1;
|
||||
}
|
||||
}
|
||||
const info = this.ranges[this.nextIdx];
|
||||
this.ignoreSelectionChange = true;
|
||||
try {
|
||||
const pos = info.range.getStartPosition();
|
||||
this._editor.setPosition(pos);
|
||||
this._editor.revealRangeInCenter(info.range, scrollType);
|
||||
}
|
||||
finally {
|
||||
this.ignoreSelectionChange = false;
|
||||
}
|
||||
}
|
||||
canNavigate() {
|
||||
return this.ranges && this.ranges.length > 0;
|
||||
}
|
||||
next(scrollType = 0 /* ScrollType.Smooth */) {
|
||||
this._move(true, scrollType);
|
||||
}
|
||||
previous(scrollType = 0 /* ScrollType.Smooth */) {
|
||||
this._move(false, scrollType);
|
||||
}
|
||||
dispose() {
|
||||
super.dispose();
|
||||
this.ranges = [];
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,731 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var _a;
|
||||
import './media/diffReview.css';
|
||||
import * as nls from '../../../nls.js';
|
||||
import * as dom from '../../../base/browser/dom.js';
|
||||
import { createFastDomNode } from '../../../base/browser/fastDomNode.js';
|
||||
import { ActionBar } from '../../../base/browser/ui/actionbar/actionbar.js';
|
||||
import { DomScrollableElement } from '../../../base/browser/ui/scrollbar/scrollableElement.js';
|
||||
import { Action } from '../../../base/common/actions.js';
|
||||
import { Disposable } from '../../../base/common/lifecycle.js';
|
||||
import { applyFontInfo } from '../config/domFontInfo.js';
|
||||
import { EditorAction, registerEditorAction } from '../editorExtensions.js';
|
||||
import { ICodeEditorService } from '../services/codeEditorService.js';
|
||||
import { EditorFontLigatures } from '../../common/config/editorOptions.js';
|
||||
import { LineTokens } from '../../common/tokens/lineTokens.js';
|
||||
import { Position } from '../../common/core/position.js';
|
||||
import { editorLineNumbers } from '../../common/core/editorColorRegistry.js';
|
||||
import { RenderLineInput, renderViewLine2 as renderViewLine } from '../../common/viewLayout/viewLineRenderer.js';
|
||||
import { ViewLineRenderingData } from '../../common/viewModel.js';
|
||||
import { ContextKeyExpr } from '../../../platform/contextkey/common/contextkey.js';
|
||||
import { scrollbarShadow } from '../../../platform/theme/common/colorRegistry.js';
|
||||
import { registerThemingParticipant, ThemeIcon } from '../../../platform/theme/common/themeService.js';
|
||||
import { Codicon } from '../../../base/common/codicons.js';
|
||||
import { registerIcon } from '../../../platform/theme/common/iconRegistry.js';
|
||||
import { ILanguageService } from '../../common/languages/language.js';
|
||||
const DIFF_LINES_PADDING = 3;
|
||||
class DiffEntry {
|
||||
constructor(originalLineStart, originalLineEnd, modifiedLineStart, modifiedLineEnd) {
|
||||
this.originalLineStart = originalLineStart;
|
||||
this.originalLineEnd = originalLineEnd;
|
||||
this.modifiedLineStart = modifiedLineStart;
|
||||
this.modifiedLineEnd = modifiedLineEnd;
|
||||
}
|
||||
getType() {
|
||||
if (this.originalLineStart === 0) {
|
||||
return 1 /* DiffEntryType.Insert */;
|
||||
}
|
||||
if (this.modifiedLineStart === 0) {
|
||||
return 2 /* DiffEntryType.Delete */;
|
||||
}
|
||||
return 0 /* DiffEntryType.Equal */;
|
||||
}
|
||||
}
|
||||
class Diff {
|
||||
constructor(entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
}
|
||||
const diffReviewInsertIcon = registerIcon('diff-review-insert', Codicon.add, nls.localize('diffReviewInsertIcon', 'Icon for \'Insert\' in diff review.'));
|
||||
const diffReviewRemoveIcon = registerIcon('diff-review-remove', Codicon.remove, nls.localize('diffReviewRemoveIcon', 'Icon for \'Remove\' in diff review.'));
|
||||
const diffReviewCloseIcon = registerIcon('diff-review-close', Codicon.close, nls.localize('diffReviewCloseIcon', 'Icon for \'Close\' in diff review.'));
|
||||
let DiffReview = class DiffReview extends Disposable {
|
||||
constructor(diffEditor, _languageService) {
|
||||
super();
|
||||
this._languageService = _languageService;
|
||||
this._width = 0;
|
||||
this._diffEditor = diffEditor;
|
||||
this._isVisible = false;
|
||||
this.shadow = createFastDomNode(document.createElement('div'));
|
||||
this.shadow.setClassName('diff-review-shadow');
|
||||
this.actionBarContainer = createFastDomNode(document.createElement('div'));
|
||||
this.actionBarContainer.setClassName('diff-review-actions');
|
||||
this._actionBar = this._register(new ActionBar(this.actionBarContainer.domNode));
|
||||
this._actionBar.push(new Action('diffreview.close', nls.localize('label.close', "Close"), 'close-diff-review ' + ThemeIcon.asClassName(diffReviewCloseIcon), true, () => __awaiter(this, void 0, void 0, function* () { return this.hide(); })), { label: false, icon: true });
|
||||
this.domNode = createFastDomNode(document.createElement('div'));
|
||||
this.domNode.setClassName('diff-review monaco-editor-background');
|
||||
this._content = createFastDomNode(document.createElement('div'));
|
||||
this._content.setClassName('diff-review-content');
|
||||
this._content.setAttribute('role', 'code');
|
||||
this.scrollbar = this._register(new DomScrollableElement(this._content.domNode, {}));
|
||||
this.domNode.domNode.appendChild(this.scrollbar.getDomNode());
|
||||
this._register(diffEditor.onDidUpdateDiff(() => {
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._diffs = this._compute();
|
||||
this._render();
|
||||
}));
|
||||
this._register(diffEditor.getModifiedEditor().onDidChangeCursorPosition(() => {
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._render();
|
||||
}));
|
||||
this._register(dom.addStandardDisposableListener(this.domNode.domNode, 'click', (e) => {
|
||||
e.preventDefault();
|
||||
const row = dom.findParentWithClass(e.target, 'diff-review-row');
|
||||
if (row) {
|
||||
this._goToRow(row);
|
||||
}
|
||||
}));
|
||||
this._register(dom.addStandardDisposableListener(this.domNode.domNode, 'keydown', (e) => {
|
||||
if (e.equals(18 /* KeyCode.DownArrow */)
|
||||
|| e.equals(2048 /* KeyMod.CtrlCmd */ | 18 /* KeyCode.DownArrow */)
|
||||
|| e.equals(512 /* KeyMod.Alt */ | 18 /* KeyCode.DownArrow */)) {
|
||||
e.preventDefault();
|
||||
this._goToRow(this._getNextRow());
|
||||
}
|
||||
if (e.equals(16 /* KeyCode.UpArrow */)
|
||||
|| e.equals(2048 /* KeyMod.CtrlCmd */ | 16 /* KeyCode.UpArrow */)
|
||||
|| e.equals(512 /* KeyMod.Alt */ | 16 /* KeyCode.UpArrow */)) {
|
||||
e.preventDefault();
|
||||
this._goToRow(this._getPrevRow());
|
||||
}
|
||||
if (e.equals(9 /* KeyCode.Escape */)
|
||||
|| e.equals(2048 /* KeyMod.CtrlCmd */ | 9 /* KeyCode.Escape */)
|
||||
|| e.equals(512 /* KeyMod.Alt */ | 9 /* KeyCode.Escape */)
|
||||
|| e.equals(1024 /* KeyMod.Shift */ | 9 /* KeyCode.Escape */)) {
|
||||
e.preventDefault();
|
||||
this.hide();
|
||||
}
|
||||
if (e.equals(10 /* KeyCode.Space */)
|
||||
|| e.equals(3 /* KeyCode.Enter */)) {
|
||||
e.preventDefault();
|
||||
this.accept();
|
||||
}
|
||||
}));
|
||||
this._diffs = [];
|
||||
this._currentDiff = null;
|
||||
}
|
||||
prev() {
|
||||
let index = 0;
|
||||
if (!this._isVisible) {
|
||||
this._diffs = this._compute();
|
||||
}
|
||||
if (this._isVisible) {
|
||||
let currentIndex = -1;
|
||||
for (let i = 0, len = this._diffs.length; i < len; i++) {
|
||||
if (this._diffs[i] === this._currentDiff) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
index = (this._diffs.length + currentIndex - 1);
|
||||
}
|
||||
else {
|
||||
index = this._findDiffIndex(this._diffEditor.getPosition());
|
||||
}
|
||||
if (this._diffs.length === 0) {
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
index = index % this._diffs.length;
|
||||
const entries = this._diffs[index].entries;
|
||||
this._diffEditor.setPosition(new Position(entries[0].modifiedLineStart, 1));
|
||||
this._diffEditor.setSelection({ startColumn: 1, startLineNumber: entries[0].modifiedLineStart, endColumn: 1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */, endLineNumber: entries[entries.length - 1].modifiedLineEnd });
|
||||
this._isVisible = true;
|
||||
this._diffEditor.doLayout();
|
||||
this._render();
|
||||
this._goToRow(this._getNextRow());
|
||||
}
|
||||
next() {
|
||||
let index = 0;
|
||||
if (!this._isVisible) {
|
||||
this._diffs = this._compute();
|
||||
}
|
||||
if (this._isVisible) {
|
||||
let currentIndex = -1;
|
||||
for (let i = 0, len = this._diffs.length; i < len; i++) {
|
||||
if (this._diffs[i] === this._currentDiff) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
index = (currentIndex + 1);
|
||||
}
|
||||
else {
|
||||
index = this._findDiffIndex(this._diffEditor.getPosition());
|
||||
}
|
||||
if (this._diffs.length === 0) {
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
index = index % this._diffs.length;
|
||||
const entries = this._diffs[index].entries;
|
||||
this._diffEditor.setPosition(new Position(entries[0].modifiedLineStart, 1));
|
||||
this._diffEditor.setSelection({ startColumn: 1, startLineNumber: entries[0].modifiedLineStart, endColumn: 1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */, endLineNumber: entries[entries.length - 1].modifiedLineEnd });
|
||||
this._isVisible = true;
|
||||
this._diffEditor.doLayout();
|
||||
this._render();
|
||||
this._goToRow(this._getNextRow());
|
||||
}
|
||||
accept() {
|
||||
let jumpToLineNumber = -1;
|
||||
const current = this._getCurrentFocusedRow();
|
||||
if (current) {
|
||||
const lineNumber = parseInt(current.getAttribute('data-line'), 10);
|
||||
if (!isNaN(lineNumber)) {
|
||||
jumpToLineNumber = lineNumber;
|
||||
}
|
||||
}
|
||||
this.hide();
|
||||
if (jumpToLineNumber !== -1) {
|
||||
this._diffEditor.setPosition(new Position(jumpToLineNumber, 1));
|
||||
this._diffEditor.revealPosition(new Position(jumpToLineNumber, 1), 1 /* ScrollType.Immediate */);
|
||||
}
|
||||
}
|
||||
hide() {
|
||||
this._isVisible = false;
|
||||
this._diffEditor.updateOptions({ readOnly: false });
|
||||
this._diffEditor.focus();
|
||||
this._diffEditor.doLayout();
|
||||
this._render();
|
||||
}
|
||||
_getPrevRow() {
|
||||
const current = this._getCurrentFocusedRow();
|
||||
if (!current) {
|
||||
return this._getFirstRow();
|
||||
}
|
||||
if (current.previousElementSibling) {
|
||||
return current.previousElementSibling;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
_getNextRow() {
|
||||
const current = this._getCurrentFocusedRow();
|
||||
if (!current) {
|
||||
return this._getFirstRow();
|
||||
}
|
||||
if (current.nextElementSibling) {
|
||||
return current.nextElementSibling;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
_getFirstRow() {
|
||||
return this.domNode.domNode.querySelector('.diff-review-row');
|
||||
}
|
||||
_getCurrentFocusedRow() {
|
||||
const result = document.activeElement;
|
||||
if (result && /diff-review-row/.test(result.className)) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
_goToRow(row) {
|
||||
const prev = this._getCurrentFocusedRow();
|
||||
row.tabIndex = 0;
|
||||
row.focus();
|
||||
if (prev && prev !== row) {
|
||||
prev.tabIndex = -1;
|
||||
}
|
||||
this.scrollbar.scanDomNode();
|
||||
}
|
||||
isVisible() {
|
||||
return this._isVisible;
|
||||
}
|
||||
layout(top, width, height) {
|
||||
this._width = width;
|
||||
this.shadow.setTop(top - 6);
|
||||
this.shadow.setWidth(width);
|
||||
this.shadow.setHeight(this._isVisible ? 6 : 0);
|
||||
this.domNode.setTop(top);
|
||||
this.domNode.setWidth(width);
|
||||
this.domNode.setHeight(height);
|
||||
this._content.setHeight(height);
|
||||
this._content.setWidth(width);
|
||||
if (this._isVisible) {
|
||||
this.actionBarContainer.setAttribute('aria-hidden', 'false');
|
||||
this.actionBarContainer.setDisplay('block');
|
||||
}
|
||||
else {
|
||||
this.actionBarContainer.setAttribute('aria-hidden', 'true');
|
||||
this.actionBarContainer.setDisplay('none');
|
||||
}
|
||||
}
|
||||
_compute() {
|
||||
const lineChanges = this._diffEditor.getLineChanges();
|
||||
if (!lineChanges || lineChanges.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const originalModel = this._diffEditor.getOriginalEditor().getModel();
|
||||
const modifiedModel = this._diffEditor.getModifiedEditor().getModel();
|
||||
if (!originalModel || !modifiedModel) {
|
||||
return [];
|
||||
}
|
||||
return DiffReview._mergeAdjacent(lineChanges, originalModel.getLineCount(), modifiedModel.getLineCount());
|
||||
}
|
||||
static _mergeAdjacent(lineChanges, originalLineCount, modifiedLineCount) {
|
||||
if (!lineChanges || lineChanges.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const diffs = [];
|
||||
let diffsLength = 0;
|
||||
for (let i = 0, len = lineChanges.length; i < len; i++) {
|
||||
const lineChange = lineChanges[i];
|
||||
const originalStart = lineChange.originalStartLineNumber;
|
||||
const originalEnd = lineChange.originalEndLineNumber;
|
||||
const modifiedStart = lineChange.modifiedStartLineNumber;
|
||||
const modifiedEnd = lineChange.modifiedEndLineNumber;
|
||||
const r = [];
|
||||
let rLength = 0;
|
||||
// Emit before anchors
|
||||
{
|
||||
const originalEqualAbove = (originalEnd === 0 ? originalStart : originalStart - 1);
|
||||
const modifiedEqualAbove = (modifiedEnd === 0 ? modifiedStart : modifiedStart - 1);
|
||||
// Make sure we don't step into the previous diff
|
||||
let minOriginal = 1;
|
||||
let minModified = 1;
|
||||
if (i > 0) {
|
||||
const prevLineChange = lineChanges[i - 1];
|
||||
if (prevLineChange.originalEndLineNumber === 0) {
|
||||
minOriginal = prevLineChange.originalStartLineNumber + 1;
|
||||
}
|
||||
else {
|
||||
minOriginal = prevLineChange.originalEndLineNumber + 1;
|
||||
}
|
||||
if (prevLineChange.modifiedEndLineNumber === 0) {
|
||||
minModified = prevLineChange.modifiedStartLineNumber + 1;
|
||||
}
|
||||
else {
|
||||
minModified = prevLineChange.modifiedEndLineNumber + 1;
|
||||
}
|
||||
}
|
||||
let fromOriginal = originalEqualAbove - DIFF_LINES_PADDING + 1;
|
||||
let fromModified = modifiedEqualAbove - DIFF_LINES_PADDING + 1;
|
||||
if (fromOriginal < minOriginal) {
|
||||
const delta = minOriginal - fromOriginal;
|
||||
fromOriginal = fromOriginal + delta;
|
||||
fromModified = fromModified + delta;
|
||||
}
|
||||
if (fromModified < minModified) {
|
||||
const delta = minModified - fromModified;
|
||||
fromOriginal = fromOriginal + delta;
|
||||
fromModified = fromModified + delta;
|
||||
}
|
||||
r[rLength++] = new DiffEntry(fromOriginal, originalEqualAbove, fromModified, modifiedEqualAbove);
|
||||
}
|
||||
// Emit deleted lines
|
||||
{
|
||||
if (originalEnd !== 0) {
|
||||
r[rLength++] = new DiffEntry(originalStart, originalEnd, 0, 0);
|
||||
}
|
||||
}
|
||||
// Emit inserted lines
|
||||
{
|
||||
if (modifiedEnd !== 0) {
|
||||
r[rLength++] = new DiffEntry(0, 0, modifiedStart, modifiedEnd);
|
||||
}
|
||||
}
|
||||
// Emit after anchors
|
||||
{
|
||||
const originalEqualBelow = (originalEnd === 0 ? originalStart + 1 : originalEnd + 1);
|
||||
const modifiedEqualBelow = (modifiedEnd === 0 ? modifiedStart + 1 : modifiedEnd + 1);
|
||||
// Make sure we don't step into the next diff
|
||||
let maxOriginal = originalLineCount;
|
||||
let maxModified = modifiedLineCount;
|
||||
if (i + 1 < len) {
|
||||
const nextLineChange = lineChanges[i + 1];
|
||||
if (nextLineChange.originalEndLineNumber === 0) {
|
||||
maxOriginal = nextLineChange.originalStartLineNumber;
|
||||
}
|
||||
else {
|
||||
maxOriginal = nextLineChange.originalStartLineNumber - 1;
|
||||
}
|
||||
if (nextLineChange.modifiedEndLineNumber === 0) {
|
||||
maxModified = nextLineChange.modifiedStartLineNumber;
|
||||
}
|
||||
else {
|
||||
maxModified = nextLineChange.modifiedStartLineNumber - 1;
|
||||
}
|
||||
}
|
||||
let toOriginal = originalEqualBelow + DIFF_LINES_PADDING - 1;
|
||||
let toModified = modifiedEqualBelow + DIFF_LINES_PADDING - 1;
|
||||
if (toOriginal > maxOriginal) {
|
||||
const delta = maxOriginal - toOriginal;
|
||||
toOriginal = toOriginal + delta;
|
||||
toModified = toModified + delta;
|
||||
}
|
||||
if (toModified > maxModified) {
|
||||
const delta = maxModified - toModified;
|
||||
toOriginal = toOriginal + delta;
|
||||
toModified = toModified + delta;
|
||||
}
|
||||
r[rLength++] = new DiffEntry(originalEqualBelow, toOriginal, modifiedEqualBelow, toModified);
|
||||
}
|
||||
diffs[diffsLength++] = new Diff(r);
|
||||
}
|
||||
// Merge adjacent diffs
|
||||
let curr = diffs[0].entries;
|
||||
const r = [];
|
||||
let rLength = 0;
|
||||
for (let i = 1, len = diffs.length; i < len; i++) {
|
||||
const thisDiff = diffs[i].entries;
|
||||
const currLast = curr[curr.length - 1];
|
||||
const thisFirst = thisDiff[0];
|
||||
if (currLast.getType() === 0 /* DiffEntryType.Equal */
|
||||
&& thisFirst.getType() === 0 /* DiffEntryType.Equal */
|
||||
&& thisFirst.originalLineStart <= currLast.originalLineEnd) {
|
||||
// We are dealing with equal lines that overlap
|
||||
curr[curr.length - 1] = new DiffEntry(currLast.originalLineStart, thisFirst.originalLineEnd, currLast.modifiedLineStart, thisFirst.modifiedLineEnd);
|
||||
curr = curr.concat(thisDiff.slice(1));
|
||||
continue;
|
||||
}
|
||||
r[rLength++] = new Diff(curr);
|
||||
curr = thisDiff;
|
||||
}
|
||||
r[rLength++] = new Diff(curr);
|
||||
return r;
|
||||
}
|
||||
_findDiffIndex(pos) {
|
||||
const lineNumber = pos.lineNumber;
|
||||
for (let i = 0, len = this._diffs.length; i < len; i++) {
|
||||
const diff = this._diffs[i].entries;
|
||||
const lastModifiedLine = diff[diff.length - 1].modifiedLineEnd;
|
||||
if (lineNumber <= lastModifiedLine) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
_render() {
|
||||
const originalOptions = this._diffEditor.getOriginalEditor().getOptions();
|
||||
const modifiedOptions = this._diffEditor.getModifiedEditor().getOptions();
|
||||
const originalModel = this._diffEditor.getOriginalEditor().getModel();
|
||||
const modifiedModel = this._diffEditor.getModifiedEditor().getModel();
|
||||
const originalModelOpts = originalModel.getOptions();
|
||||
const modifiedModelOpts = modifiedModel.getOptions();
|
||||
if (!this._isVisible || !originalModel || !modifiedModel) {
|
||||
dom.clearNode(this._content.domNode);
|
||||
this._currentDiff = null;
|
||||
this.scrollbar.scanDomNode();
|
||||
return;
|
||||
}
|
||||
this._diffEditor.updateOptions({ readOnly: true });
|
||||
const diffIndex = this._findDiffIndex(this._diffEditor.getPosition());
|
||||
if (this._diffs[diffIndex] === this._currentDiff) {
|
||||
return;
|
||||
}
|
||||
this._currentDiff = this._diffs[diffIndex];
|
||||
const diffs = this._diffs[diffIndex].entries;
|
||||
const container = document.createElement('div');
|
||||
container.className = 'diff-review-table';
|
||||
container.setAttribute('role', 'list');
|
||||
container.setAttribute('aria-label', 'Difference review. Use "Stage | Unstage | Revert Selected Ranges" commands');
|
||||
applyFontInfo(container, modifiedOptions.get(46 /* EditorOption.fontInfo */));
|
||||
let minOriginalLine = 0;
|
||||
let maxOriginalLine = 0;
|
||||
let minModifiedLine = 0;
|
||||
let maxModifiedLine = 0;
|
||||
for (let i = 0, len = diffs.length; i < len; i++) {
|
||||
const diffEntry = diffs[i];
|
||||
const originalLineStart = diffEntry.originalLineStart;
|
||||
const originalLineEnd = diffEntry.originalLineEnd;
|
||||
const modifiedLineStart = diffEntry.modifiedLineStart;
|
||||
const modifiedLineEnd = diffEntry.modifiedLineEnd;
|
||||
if (originalLineStart !== 0 && ((minOriginalLine === 0 || originalLineStart < minOriginalLine))) {
|
||||
minOriginalLine = originalLineStart;
|
||||
}
|
||||
if (originalLineEnd !== 0 && ((maxOriginalLine === 0 || originalLineEnd > maxOriginalLine))) {
|
||||
maxOriginalLine = originalLineEnd;
|
||||
}
|
||||
if (modifiedLineStart !== 0 && ((minModifiedLine === 0 || modifiedLineStart < minModifiedLine))) {
|
||||
minModifiedLine = modifiedLineStart;
|
||||
}
|
||||
if (modifiedLineEnd !== 0 && ((maxModifiedLine === 0 || modifiedLineEnd > maxModifiedLine))) {
|
||||
maxModifiedLine = modifiedLineEnd;
|
||||
}
|
||||
}
|
||||
const header = document.createElement('div');
|
||||
header.className = 'diff-review-row';
|
||||
const cell = document.createElement('div');
|
||||
cell.className = 'diff-review-cell diff-review-summary';
|
||||
const originalChangedLinesCnt = maxOriginalLine - minOriginalLine + 1;
|
||||
const modifiedChangedLinesCnt = maxModifiedLine - minModifiedLine + 1;
|
||||
cell.appendChild(document.createTextNode(`${diffIndex + 1}/${this._diffs.length}: @@ -${minOriginalLine},${originalChangedLinesCnt} +${minModifiedLine},${modifiedChangedLinesCnt} @@`));
|
||||
header.setAttribute('data-line', String(minModifiedLine));
|
||||
const getAriaLines = (lines) => {
|
||||
if (lines === 0) {
|
||||
return nls.localize('no_lines_changed', "no lines changed");
|
||||
}
|
||||
else if (lines === 1) {
|
||||
return nls.localize('one_line_changed', "1 line changed");
|
||||
}
|
||||
else {
|
||||
return nls.localize('more_lines_changed', "{0} lines changed", lines);
|
||||
}
|
||||
};
|
||||
const originalChangedLinesCntAria = getAriaLines(originalChangedLinesCnt);
|
||||
const modifiedChangedLinesCntAria = getAriaLines(modifiedChangedLinesCnt);
|
||||
header.setAttribute('aria-label', nls.localize({
|
||||
key: 'header',
|
||||
comment: [
|
||||
'This is the ARIA label for a git diff header.',
|
||||
'A git diff header looks like this: @@ -154,12 +159,39 @@.',
|
||||
'That encodes that at original line 154 (which is now line 159), 12 lines were removed/changed with 39 lines.',
|
||||
'Variables 0 and 1 refer to the diff index out of total number of diffs.',
|
||||
'Variables 2 and 4 will be numbers (a line number).',
|
||||
'Variables 3 and 5 will be "no lines changed", "1 line changed" or "X lines changed", localized separately.'
|
||||
]
|
||||
}, "Difference {0} of {1}: original line {2}, {3}, modified line {4}, {5}", (diffIndex + 1), this._diffs.length, minOriginalLine, originalChangedLinesCntAria, minModifiedLine, modifiedChangedLinesCntAria));
|
||||
header.appendChild(cell);
|
||||
// @@ -504,7 +517,7 @@
|
||||
header.setAttribute('role', 'listitem');
|
||||
container.appendChild(header);
|
||||
const lineHeight = modifiedOptions.get(61 /* EditorOption.lineHeight */);
|
||||
let modLine = minModifiedLine;
|
||||
for (let i = 0, len = diffs.length; i < len; i++) {
|
||||
const diffEntry = diffs[i];
|
||||
DiffReview._renderSection(container, diffEntry, modLine, lineHeight, this._width, originalOptions, originalModel, originalModelOpts, modifiedOptions, modifiedModel, modifiedModelOpts, this._languageService.languageIdCodec);
|
||||
if (diffEntry.modifiedLineStart !== 0) {
|
||||
modLine = diffEntry.modifiedLineEnd;
|
||||
}
|
||||
}
|
||||
dom.clearNode(this._content.domNode);
|
||||
this._content.domNode.appendChild(container);
|
||||
this.scrollbar.scanDomNode();
|
||||
}
|
||||
static _renderSection(dest, diffEntry, modLine, lineHeight, width, originalOptions, originalModel, originalModelOpts, modifiedOptions, modifiedModel, modifiedModelOpts, languageIdCodec) {
|
||||
const type = diffEntry.getType();
|
||||
let rowClassName = 'diff-review-row';
|
||||
let lineNumbersExtraClassName = '';
|
||||
const spacerClassName = 'diff-review-spacer';
|
||||
let spacerIcon = null;
|
||||
switch (type) {
|
||||
case 1 /* DiffEntryType.Insert */:
|
||||
rowClassName = 'diff-review-row line-insert';
|
||||
lineNumbersExtraClassName = ' char-insert';
|
||||
spacerIcon = diffReviewInsertIcon;
|
||||
break;
|
||||
case 2 /* DiffEntryType.Delete */:
|
||||
rowClassName = 'diff-review-row line-delete';
|
||||
lineNumbersExtraClassName = ' char-delete';
|
||||
spacerIcon = diffReviewRemoveIcon;
|
||||
break;
|
||||
}
|
||||
const originalLineStart = diffEntry.originalLineStart;
|
||||
const originalLineEnd = diffEntry.originalLineEnd;
|
||||
const modifiedLineStart = diffEntry.modifiedLineStart;
|
||||
const modifiedLineEnd = diffEntry.modifiedLineEnd;
|
||||
const cnt = Math.max(modifiedLineEnd - modifiedLineStart, originalLineEnd - originalLineStart);
|
||||
const originalLayoutInfo = originalOptions.get(133 /* EditorOption.layoutInfo */);
|
||||
const originalLineNumbersWidth = originalLayoutInfo.glyphMarginWidth + originalLayoutInfo.lineNumbersWidth;
|
||||
const modifiedLayoutInfo = modifiedOptions.get(133 /* EditorOption.layoutInfo */);
|
||||
const modifiedLineNumbersWidth = 10 + modifiedLayoutInfo.glyphMarginWidth + modifiedLayoutInfo.lineNumbersWidth;
|
||||
for (let i = 0; i <= cnt; i++) {
|
||||
const originalLine = (originalLineStart === 0 ? 0 : originalLineStart + i);
|
||||
const modifiedLine = (modifiedLineStart === 0 ? 0 : modifiedLineStart + i);
|
||||
const row = document.createElement('div');
|
||||
row.style.minWidth = width + 'px';
|
||||
row.className = rowClassName;
|
||||
row.setAttribute('role', 'listitem');
|
||||
if (modifiedLine !== 0) {
|
||||
modLine = modifiedLine;
|
||||
}
|
||||
row.setAttribute('data-line', String(modLine));
|
||||
const cell = document.createElement('div');
|
||||
cell.className = 'diff-review-cell';
|
||||
cell.style.height = `${lineHeight}px`;
|
||||
row.appendChild(cell);
|
||||
const originalLineNumber = document.createElement('span');
|
||||
originalLineNumber.style.width = (originalLineNumbersWidth + 'px');
|
||||
originalLineNumber.style.minWidth = (originalLineNumbersWidth + 'px');
|
||||
originalLineNumber.className = 'diff-review-line-number' + lineNumbersExtraClassName;
|
||||
if (originalLine !== 0) {
|
||||
originalLineNumber.appendChild(document.createTextNode(String(originalLine)));
|
||||
}
|
||||
else {
|
||||
originalLineNumber.innerText = '\u00a0';
|
||||
}
|
||||
cell.appendChild(originalLineNumber);
|
||||
const modifiedLineNumber = document.createElement('span');
|
||||
modifiedLineNumber.style.width = (modifiedLineNumbersWidth + 'px');
|
||||
modifiedLineNumber.style.minWidth = (modifiedLineNumbersWidth + 'px');
|
||||
modifiedLineNumber.style.paddingRight = '10px';
|
||||
modifiedLineNumber.className = 'diff-review-line-number' + lineNumbersExtraClassName;
|
||||
if (modifiedLine !== 0) {
|
||||
modifiedLineNumber.appendChild(document.createTextNode(String(modifiedLine)));
|
||||
}
|
||||
else {
|
||||
modifiedLineNumber.innerText = '\u00a0';
|
||||
}
|
||||
cell.appendChild(modifiedLineNumber);
|
||||
const spacer = document.createElement('span');
|
||||
spacer.className = spacerClassName;
|
||||
if (spacerIcon) {
|
||||
const spacerCodicon = document.createElement('span');
|
||||
spacerCodicon.className = ThemeIcon.asClassName(spacerIcon);
|
||||
spacerCodicon.innerText = '\u00a0\u00a0';
|
||||
spacer.appendChild(spacerCodicon);
|
||||
}
|
||||
else {
|
||||
spacer.innerText = '\u00a0\u00a0';
|
||||
}
|
||||
cell.appendChild(spacer);
|
||||
let lineContent;
|
||||
if (modifiedLine !== 0) {
|
||||
let html = this._renderLine(modifiedModel, modifiedOptions, modifiedModelOpts.tabSize, modifiedLine, languageIdCodec);
|
||||
if (DiffReview._ttPolicy) {
|
||||
html = DiffReview._ttPolicy.createHTML(html);
|
||||
}
|
||||
cell.insertAdjacentHTML('beforeend', html);
|
||||
lineContent = modifiedModel.getLineContent(modifiedLine);
|
||||
}
|
||||
else {
|
||||
let html = this._renderLine(originalModel, originalOptions, originalModelOpts.tabSize, originalLine, languageIdCodec);
|
||||
if (DiffReview._ttPolicy) {
|
||||
html = DiffReview._ttPolicy.createHTML(html);
|
||||
}
|
||||
cell.insertAdjacentHTML('beforeend', html);
|
||||
lineContent = originalModel.getLineContent(originalLine);
|
||||
}
|
||||
if (lineContent.length === 0) {
|
||||
lineContent = nls.localize('blankLine', "blank");
|
||||
}
|
||||
let ariaLabel = '';
|
||||
switch (type) {
|
||||
case 0 /* DiffEntryType.Equal */:
|
||||
if (originalLine === modifiedLine) {
|
||||
ariaLabel = nls.localize({ key: 'unchangedLine', comment: ['The placeholders are contents of the line and should not be translated.'] }, "{0} unchanged line {1}", lineContent, originalLine);
|
||||
}
|
||||
else {
|
||||
ariaLabel = nls.localize('equalLine', "{0} original line {1} modified line {2}", lineContent, originalLine, modifiedLine);
|
||||
}
|
||||
break;
|
||||
case 1 /* DiffEntryType.Insert */:
|
||||
ariaLabel = nls.localize('insertLine', "+ {0} modified line {1}", lineContent, modifiedLine);
|
||||
break;
|
||||
case 2 /* DiffEntryType.Delete */:
|
||||
ariaLabel = nls.localize('deleteLine', "- {0} original line {1}", lineContent, originalLine);
|
||||
break;
|
||||
}
|
||||
row.setAttribute('aria-label', ariaLabel);
|
||||
dest.appendChild(row);
|
||||
}
|
||||
}
|
||||
static _renderLine(model, options, tabSize, lineNumber, languageIdCodec) {
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
const fontInfo = options.get(46 /* EditorOption.fontInfo */);
|
||||
const lineTokens = LineTokens.createEmpty(lineContent, languageIdCodec);
|
||||
const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII());
|
||||
const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL());
|
||||
const r = renderViewLine(new RenderLineInput((fontInfo.isMonospace && !options.get(29 /* EditorOption.disableMonospaceOptimizations */)), fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, isBasicASCII, containsRTL, 0, lineTokens, [], tabSize, 0, fontInfo.spaceWidth, fontInfo.middotWidth, fontInfo.wsmiddotWidth, options.get(107 /* EditorOption.stopRenderingLineAfter */), options.get(90 /* EditorOption.renderWhitespace */), options.get(85 /* EditorOption.renderControlCharacters */), options.get(47 /* EditorOption.fontLigatures */) !== EditorFontLigatures.OFF, null));
|
||||
return r.html;
|
||||
}
|
||||
};
|
||||
DiffReview._ttPolicy = (_a = window.trustedTypes) === null || _a === void 0 ? void 0 : _a.createPolicy('diffReview', { createHTML: value => value });
|
||||
DiffReview = __decorate([
|
||||
__param(1, ILanguageService)
|
||||
], DiffReview);
|
||||
export { DiffReview };
|
||||
// theming
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
const lineNumbers = theme.getColor(editorLineNumbers);
|
||||
if (lineNumbers) {
|
||||
collector.addRule(`.monaco-diff-editor .diff-review-line-number { color: ${lineNumbers}; }`);
|
||||
}
|
||||
const shadow = theme.getColor(scrollbarShadow);
|
||||
if (shadow) {
|
||||
collector.addRule(`.monaco-diff-editor .diff-review-shadow { box-shadow: ${shadow} 0 -6px 6px -6px inset; }`);
|
||||
}
|
||||
});
|
||||
class DiffReviewNext extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.diffReview.next',
|
||||
label: nls.localize('editor.action.diffReview.next', "Go to Next Difference"),
|
||||
alias: 'Go to Next Difference',
|
||||
precondition: ContextKeyExpr.has('isInDiffEditor'),
|
||||
kbOpts: {
|
||||
kbExpr: null,
|
||||
primary: 65 /* KeyCode.F7 */,
|
||||
weight: 100 /* KeybindingWeight.EditorContrib */
|
||||
}
|
||||
});
|
||||
}
|
||||
run(accessor, editor) {
|
||||
const diffEditor = findFocusedDiffEditor(accessor);
|
||||
if (diffEditor) {
|
||||
diffEditor.diffReviewNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
class DiffReviewPrev extends EditorAction {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.diffReview.prev',
|
||||
label: nls.localize('editor.action.diffReview.prev', "Go to Previous Difference"),
|
||||
alias: 'Go to Previous Difference',
|
||||
precondition: ContextKeyExpr.has('isInDiffEditor'),
|
||||
kbOpts: {
|
||||
kbExpr: null,
|
||||
primary: 1024 /* KeyMod.Shift */ | 65 /* KeyCode.F7 */,
|
||||
weight: 100 /* KeybindingWeight.EditorContrib */
|
||||
}
|
||||
});
|
||||
}
|
||||
run(accessor, editor) {
|
||||
const diffEditor = findFocusedDiffEditor(accessor);
|
||||
if (diffEditor) {
|
||||
diffEditor.diffReviewPrev();
|
||||
}
|
||||
}
|
||||
}
|
||||
function findFocusedDiffEditor(accessor) {
|
||||
const codeEditorService = accessor.get(ICodeEditorService);
|
||||
const diffEditors = codeEditorService.listDiffEditors();
|
||||
const activeCodeEditor = codeEditorService.getActiveCodeEditor();
|
||||
if (!activeCodeEditor) {
|
||||
return null;
|
||||
}
|
||||
for (let i = 0, len = diffEditors.length; i < len; i++) {
|
||||
const diffEditor = diffEditors[i];
|
||||
if (diffEditor.getModifiedEditor().getId() === activeCodeEditor.getId() || diffEditor.getOriginalEditor().getId() === activeCodeEditor.getId()) {
|
||||
return diffEditor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
registerEditorAction(DiffReviewNext);
|
||||
registerEditorAction(DiffReviewPrev);
|
||||
@@ -0,0 +1,57 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
import * as objects from '../../../base/common/objects.js';
|
||||
import { ICodeEditorService } from '../services/codeEditorService.js';
|
||||
import { CodeEditorWidget } from './codeEditorWidget.js';
|
||||
import { ICommandService } from '../../../platform/commands/common/commands.js';
|
||||
import { IContextKeyService } from '../../../platform/contextkey/common/contextkey.js';
|
||||
import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
|
||||
import { INotificationService } from '../../../platform/notification/common/notification.js';
|
||||
import { IThemeService } from '../../../platform/theme/common/themeService.js';
|
||||
import { IAccessibilityService } from '../../../platform/accessibility/common/accessibility.js';
|
||||
import { ILanguageConfigurationService } from '../../common/languages/languageConfigurationRegistry.js';
|
||||
import { ILanguageFeaturesService } from '../../common/services/languageFeatures.js';
|
||||
let EmbeddedCodeEditorWidget = class EmbeddedCodeEditorWidget extends CodeEditorWidget {
|
||||
constructor(domElement, options, parentEditor, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService, languageConfigurationService, languageFeaturesService) {
|
||||
super(domElement, Object.assign(Object.assign({}, parentEditor.getRawOptions()), { overflowWidgetsDomNode: parentEditor.getOverflowWidgetsDomNode() }), {}, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService, languageConfigurationService, languageFeaturesService);
|
||||
this._parentEditor = parentEditor;
|
||||
this._overwriteOptions = options;
|
||||
// Overwrite parent's options
|
||||
super.updateOptions(this._overwriteOptions);
|
||||
this._register(parentEditor.onDidChangeConfiguration((e) => this._onParentConfigurationChanged(e)));
|
||||
}
|
||||
getParentEditor() {
|
||||
return this._parentEditor;
|
||||
}
|
||||
_onParentConfigurationChanged(e) {
|
||||
super.updateOptions(this._parentEditor.getRawOptions());
|
||||
super.updateOptions(this._overwriteOptions);
|
||||
}
|
||||
updateOptions(newOptions) {
|
||||
objects.mixin(this._overwriteOptions, newOptions, true);
|
||||
super.updateOptions(this._overwriteOptions);
|
||||
}
|
||||
};
|
||||
EmbeddedCodeEditorWidget = __decorate([
|
||||
__param(3, IInstantiationService),
|
||||
__param(4, ICodeEditorService),
|
||||
__param(5, ICommandService),
|
||||
__param(6, IContextKeyService),
|
||||
__param(7, IThemeService),
|
||||
__param(8, INotificationService),
|
||||
__param(9, IAccessibilityService),
|
||||
__param(10, ILanguageConfigurationService),
|
||||
__param(11, ILanguageFeaturesService)
|
||||
], EmbeddedCodeEditorWidget);
|
||||
export { EmbeddedCodeEditorWidget };
|
||||
@@ -0,0 +1,186 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
import * as nls from '../../../nls.js';
|
||||
import * as dom from '../../../base/browser/dom.js';
|
||||
import { Action } from '../../../base/common/actions.js';
|
||||
import { Disposable } from '../../../base/common/lifecycle.js';
|
||||
import { Range } from '../../common/core/range.js';
|
||||
import { Codicon } from '../../../base/common/codicons.js';
|
||||
export class InlineDiffMargin extends Disposable {
|
||||
constructor(_viewZoneId, _marginDomNode, editor, diff, _contextMenuService, _clipboardService) {
|
||||
super();
|
||||
this._viewZoneId = _viewZoneId;
|
||||
this._marginDomNode = _marginDomNode;
|
||||
this.editor = editor;
|
||||
this.diff = diff;
|
||||
this._contextMenuService = _contextMenuService;
|
||||
this._clipboardService = _clipboardService;
|
||||
this._visibility = false;
|
||||
// make sure the diff margin shows above overlay.
|
||||
this._marginDomNode.style.zIndex = '10';
|
||||
this._diffActions = document.createElement('div');
|
||||
this._diffActions.className = Codicon.lightBulb.classNames + ' lightbulb-glyph';
|
||||
this._diffActions.style.position = 'absolute';
|
||||
const lineHeight = editor.getOption(61 /* EditorOption.lineHeight */);
|
||||
const lineFeed = editor.getModel().getEOL();
|
||||
this._diffActions.style.right = '0px';
|
||||
this._diffActions.style.visibility = 'hidden';
|
||||
this._diffActions.style.height = `${lineHeight}px`;
|
||||
this._diffActions.style.lineHeight = `${lineHeight}px`;
|
||||
this._marginDomNode.appendChild(this._diffActions);
|
||||
const actions = [];
|
||||
const isDeletion = diff.modifiedEndLineNumber === 0;
|
||||
// default action
|
||||
actions.push(new Action('diff.clipboard.copyDeletedContent', isDeletion
|
||||
? (diff.originalEndLineNumber > diff.modifiedStartLineNumber
|
||||
? nls.localize('diff.clipboard.copyDeletedLinesContent.label', "Copy deleted lines")
|
||||
: nls.localize('diff.clipboard.copyDeletedLinesContent.single.label', "Copy deleted line"))
|
||||
: (diff.originalEndLineNumber > diff.modifiedStartLineNumber
|
||||
? nls.localize('diff.clipboard.copyChangedLinesContent.label', "Copy changed lines")
|
||||
: nls.localize('diff.clipboard.copyChangedLinesContent.single.label', "Copy changed line")), undefined, true, () => __awaiter(this, void 0, void 0, function* () {
|
||||
const range = new Range(diff.originalStartLineNumber, 1, diff.originalEndLineNumber + 1, 1);
|
||||
const deletedText = diff.originalModel.getValueInRange(range);
|
||||
yield this._clipboardService.writeText(deletedText);
|
||||
})));
|
||||
let currentLineNumberOffset = 0;
|
||||
let copyLineAction = undefined;
|
||||
if (diff.originalEndLineNumber > diff.modifiedStartLineNumber) {
|
||||
copyLineAction = new Action('diff.clipboard.copyDeletedLineContent', isDeletion
|
||||
? nls.localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", diff.originalStartLineNumber)
|
||||
: nls.localize('diff.clipboard.copyChangedLineContent.label', "Copy changed line ({0})", diff.originalStartLineNumber), undefined, true, () => __awaiter(this, void 0, void 0, function* () {
|
||||
const lineContent = diff.originalModel.getLineContent(diff.originalStartLineNumber + currentLineNumberOffset);
|
||||
if (lineContent === '') {
|
||||
// empty line
|
||||
const eof = diff.originalModel.getEndOfLineSequence();
|
||||
yield this._clipboardService.writeText(eof === 0 /* EndOfLineSequence.LF */ ? '\n' : '\r\n');
|
||||
}
|
||||
else {
|
||||
yield this._clipboardService.writeText(lineContent);
|
||||
}
|
||||
}));
|
||||
actions.push(copyLineAction);
|
||||
}
|
||||
const readOnly = editor.getOption(83 /* EditorOption.readOnly */);
|
||||
if (!readOnly) {
|
||||
actions.push(new Action('diff.inline.revertChange', nls.localize('diff.inline.revertChange.label', "Revert this change"), undefined, true, () => __awaiter(this, void 0, void 0, function* () {
|
||||
const range = new Range(diff.originalStartLineNumber, 1, diff.originalEndLineNumber, diff.originalModel.getLineMaxColumn(diff.originalEndLineNumber));
|
||||
const deletedText = diff.originalModel.getValueInRange(range);
|
||||
if (diff.modifiedEndLineNumber === 0) {
|
||||
// deletion only
|
||||
const column = editor.getModel().getLineMaxColumn(diff.modifiedStartLineNumber);
|
||||
editor.executeEdits('diffEditor', [
|
||||
{
|
||||
range: new Range(diff.modifiedStartLineNumber, column, diff.modifiedStartLineNumber, column),
|
||||
text: lineFeed + deletedText
|
||||
}
|
||||
]);
|
||||
}
|
||||
else {
|
||||
const column = editor.getModel().getLineMaxColumn(diff.modifiedEndLineNumber);
|
||||
editor.executeEdits('diffEditor', [
|
||||
{
|
||||
range: new Range(diff.modifiedStartLineNumber, 1, diff.modifiedEndLineNumber, column),
|
||||
text: deletedText
|
||||
}
|
||||
]);
|
||||
}
|
||||
})));
|
||||
}
|
||||
const showContextMenu = (x, y) => {
|
||||
this._contextMenuService.showContextMenu({
|
||||
getAnchor: () => {
|
||||
return {
|
||||
x,
|
||||
y
|
||||
};
|
||||
},
|
||||
getActions: () => {
|
||||
if (copyLineAction) {
|
||||
copyLineAction.label =
|
||||
isDeletion
|
||||
? nls.localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", diff.originalStartLineNumber + currentLineNumberOffset)
|
||||
: nls.localize('diff.clipboard.copyChangedLineContent.label', "Copy changed line ({0})", diff.originalStartLineNumber + currentLineNumberOffset);
|
||||
}
|
||||
return actions;
|
||||
},
|
||||
autoSelectFirstItem: true
|
||||
});
|
||||
};
|
||||
this._register(dom.addStandardDisposableListener(this._diffActions, 'mousedown', e => {
|
||||
const { top, height } = dom.getDomNodePagePosition(this._diffActions);
|
||||
const pad = Math.floor(lineHeight / 3);
|
||||
e.preventDefault();
|
||||
showContextMenu(e.posx, top + height + pad);
|
||||
}));
|
||||
this._register(editor.onMouseMove((e) => {
|
||||
if (e.target.type === 8 /* MouseTargetType.CONTENT_VIEW_ZONE */ || e.target.type === 5 /* MouseTargetType.GUTTER_VIEW_ZONE */) {
|
||||
const viewZoneId = e.target.detail.viewZoneId;
|
||||
if (viewZoneId === this._viewZoneId) {
|
||||
this.visibility = true;
|
||||
currentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);
|
||||
}
|
||||
else {
|
||||
this.visibility = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.visibility = false;
|
||||
}
|
||||
}));
|
||||
this._register(editor.onMouseDown((e) => {
|
||||
if (!e.event.rightButton) {
|
||||
return;
|
||||
}
|
||||
if (e.target.type === 8 /* MouseTargetType.CONTENT_VIEW_ZONE */ || e.target.type === 5 /* MouseTargetType.GUTTER_VIEW_ZONE */) {
|
||||
const viewZoneId = e.target.detail.viewZoneId;
|
||||
if (viewZoneId === this._viewZoneId) {
|
||||
e.event.preventDefault();
|
||||
currentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);
|
||||
showContextMenu(e.event.posx, e.event.posy + lineHeight);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
get visibility() {
|
||||
return this._visibility;
|
||||
}
|
||||
set visibility(_visibility) {
|
||||
if (this._visibility !== _visibility) {
|
||||
this._visibility = _visibility;
|
||||
if (_visibility) {
|
||||
this._diffActions.style.visibility = 'visible';
|
||||
}
|
||||
else {
|
||||
this._diffActions.style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
}
|
||||
_updateLightBulbPosition(marginDomNode, y, lineHeight) {
|
||||
const { top } = dom.getDomNodePagePosition(marginDomNode);
|
||||
const offset = y - top;
|
||||
const lineNumberOffset = Math.floor(offset / lineHeight);
|
||||
const newTop = lineNumberOffset * lineHeight;
|
||||
this._diffActions.style.top = `${newTop}px`;
|
||||
if (this.diff.viewLineCounts) {
|
||||
let acc = 0;
|
||||
for (let i = 0; i < this.diff.viewLineCounts.length; i++) {
|
||||
acc += this.diff.viewLineCounts[i];
|
||||
if (lineNumberOffset < acc) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineNumberOffset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
/* ---------- DiffEditor ---------- */
|
||||
|
||||
.monaco-diff-editor .diffOverview {
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diffOverview .diffViewport {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* colors not externalized: using transparancy on background */
|
||||
.monaco-diff-editor.vs .diffOverview { background: rgba(0, 0, 0, 0.03); }
|
||||
.monaco-diff-editor.vs-dark .diffOverview { background: rgba(255, 255, 255, 0.01); }
|
||||
|
||||
.monaco-scrollable-element.modified-in-monaco-diff-editor.vs .scrollbar { background: rgba(0,0,0,0); }
|
||||
.monaco-scrollable-element.modified-in-monaco-diff-editor.vs-dark .scrollbar { background: rgba(0,0,0,0); }
|
||||
.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-black .scrollbar { background: none; }
|
||||
.monaco-scrollable-element.modified-in-monaco-diff-editor.hc-light .scrollbar { background: none; }
|
||||
|
||||
.monaco-scrollable-element.modified-in-monaco-diff-editor .slider {
|
||||
z-index: 10;
|
||||
}
|
||||
.modified-in-monaco-diff-editor .slider.active { background: rgba(171, 171, 171, .4); }
|
||||
.modified-in-monaco-diff-editor.hc-black .slider.active { background: none; }
|
||||
.modified-in-monaco-diff-editor.hc-light .slider.active { background: none; }
|
||||
|
||||
/* ---------- Diff ---------- */
|
||||
|
||||
.monaco-editor .insert-sign,
|
||||
.monaco-diff-editor .insert-sign,
|
||||
.monaco-editor .delete-sign,
|
||||
.monaco-diff-editor .delete-sign {
|
||||
font-size: 11px !important;
|
||||
opacity: 0.7 !important;
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
}
|
||||
.monaco-editor.hc-black .insert-sign,
|
||||
.monaco-diff-editor.hc-black .insert-sign,
|
||||
.monaco-editor.hc-black .delete-sign,
|
||||
.monaco-diff-editor.hc-black .delete-sign,
|
||||
.monaco-editor.hc-light .insert-sign,
|
||||
.monaco-diff-editor.hc-light .insert-sign,
|
||||
.monaco-editor.hc-light .delete-sign,
|
||||
.monaco-diff-editor.hc-light .delete-sign {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-deleted-margin-view-zone {
|
||||
text-align: right;
|
||||
}
|
||||
.monaco-editor .inline-added-margin-view-zone {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.monaco-editor .arrow-revert-change {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-editor .arrow-revert-change:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* ---------- Inline Diff ---------- */
|
||||
|
||||
.monaco-editor .view-zones .view-lines .view-line span {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-editor .margin-view-zones .lightbulb-glyph:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-diff-editor .diff-review-line-number {
|
||||
text-align: right;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review {
|
||||
position: absolute;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-summary {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-shadow {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-row {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-table {
|
||||
display: table;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-row {
|
||||
display: table-row;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-spacer {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-spacer > .codicon {
|
||||
font-size: 9px !important;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-actions {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.monaco-diff-editor .diff-review-actions .action-label {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 2px 0;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* -------------------- IE10 remove auto clear button -------------------- */
|
||||
|
||||
::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* All widgets */
|
||||
/* I am not a big fan of this rule */
|
||||
.monaco-editor .editor-widget input {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* -------------------- Editor -------------------- */
|
||||
|
||||
.monaco-editor {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
/* -------------------- Misc -------------------- */
|
||||
|
||||
.monaco-editor .overflow-guard {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-editor .view-overlays {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
.monaco-editor .auto-closed-character {
|
||||
opacity: 0.3;
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user