|
@ -1,6 +1,7 @@ |
|
|
'use strict'; |
|
|
'use strict'; |
|
|
import { Disposable, Event, EventEmitter, Selection, TextEditor, TextEditorSelectionChangeEvent, window } from 'vscode'; |
|
|
import { Disposable, Event, EventEmitter, Selection, TextEditor, TextEditorSelectionChangeEvent, window } from 'vscode'; |
|
|
import { isTextEditor } from '../constants'; |
|
|
import { isTextEditor } from '../constants'; |
|
|
|
|
|
import { Logger } from '../logger'; |
|
|
import { debug, Functions } from '../system'; |
|
|
import { debug, Functions } from '../system'; |
|
|
|
|
|
|
|
|
export interface LinesChangeEvent { |
|
|
export interface LinesChangeEvent { |
|
@ -29,13 +30,13 @@ export class LineTracker implements Disposable { |
|
|
|
|
|
|
|
|
dispose() { |
|
|
dispose() { |
|
|
for (const subscriber of this._subscriptions.keys()) { |
|
|
for (const subscriber of this._subscriptions.keys()) { |
|
|
this.stop(subscriber); |
|
|
|
|
|
|
|
|
this.unsubscribe(subscriber); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private onActiveTextEditorChanged(editor: TextEditor | undefined) { |
|
|
private onActiveTextEditorChanged(editor: TextEditor | undefined) { |
|
|
if (this._editor === editor) return; |
|
|
|
|
|
if (editor !== undefined && !isTextEditor(editor)) return; |
|
|
|
|
|
|
|
|
if (editor === this._editor) return; |
|
|
|
|
|
if (editor != null && !isTextEditor(editor)) return; |
|
|
|
|
|
|
|
|
this.reset(); |
|
|
this.reset(); |
|
|
this._editor = editor; |
|
|
this._editor = editor; |
|
@ -74,7 +75,7 @@ export class LineTracker implements Disposable { |
|
|
includes(selections: LineSelection[]): boolean; |
|
|
includes(selections: LineSelection[]): boolean; |
|
|
includes(line: number, options?: { activeOnly: boolean }): boolean; |
|
|
includes(line: number, options?: { activeOnly: boolean }): boolean; |
|
|
includes(lineOrSelections: number | LineSelection[], options?: { activeOnly: boolean }): boolean { |
|
|
includes(lineOrSelections: number | LineSelection[], options?: { activeOnly: boolean }): boolean { |
|
|
if (Array.isArray(lineOrSelections)) { |
|
|
|
|
|
|
|
|
if (typeof lineOrSelections !== 'number') { |
|
|
return LineTracker.includes(lineOrSelections, this._selections); |
|
|
return LineTracker.includes(lineOrSelections, this._selections); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -104,24 +105,26 @@ export class LineTracker implements Disposable { |
|
|
this._state.clear(); |
|
|
this._state.clear(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private _subscriptions = new Map<any, Disposable[]>(); |
|
|
|
|
|
|
|
|
private _subscriptions = new Map<unknown, Disposable[]>(); |
|
|
|
|
|
|
|
|
isSubscribed(subscriber: any) { |
|
|
|
|
|
|
|
|
subscribed(subscriber: unknown) { |
|
|
return this._subscriptions.has(subscriber); |
|
|
return this._subscriptions.has(subscriber); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
protected onStart?(): Disposable | undefined; |
|
|
protected onStart?(): Disposable | undefined; |
|
|
|
|
|
|
|
|
@debug({ args: false }) |
|
|
@debug({ args: false }) |
|
|
start(subscriber: any, subscription: Disposable): Disposable { |
|
|
|
|
|
|
|
|
subscribe(subscriber: unknown, subscription: Disposable): Disposable { |
|
|
|
|
|
const cc = Logger.getCorrelationContext(); |
|
|
|
|
|
|
|
|
const disposable = { |
|
|
const disposable = { |
|
|
dispose: () => this.stop(subscriber), |
|
|
|
|
|
|
|
|
dispose: () => this.unsubscribe(subscriber), |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const first = this._subscriptions.size === 0; |
|
|
const first = this._subscriptions.size === 0; |
|
|
|
|
|
|
|
|
let subs = this._subscriptions.get(subscriber); |
|
|
let subs = this._subscriptions.get(subscriber); |
|
|
if (subs === undefined) { |
|
|
|
|
|
|
|
|
if (subs == null) { |
|
|
subs = [subscription]; |
|
|
subs = [subscription]; |
|
|
this._subscriptions.set(subscriber, subs); |
|
|
this._subscriptions.set(subscriber, subs); |
|
|
} else { |
|
|
} else { |
|
@ -129,6 +132,8 @@ export class LineTracker implements Disposable { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (first) { |
|
|
if (first) { |
|
|
|
|
|
Logger.debug(cc, 'Starting line tracker...'); |
|
|
|
|
|
|
|
|
this._disposable = Disposable.from( |
|
|
this._disposable = Disposable.from( |
|
|
window.onDidChangeActiveTextEditor(Functions.debounce(this.onActiveTextEditorChanged, 0), this), |
|
|
window.onDidChangeActiveTextEditor(Functions.debounce(this.onActiveTextEditorChanged, 0), this), |
|
|
window.onDidChangeTextEditorSelection(this.onTextEditorSelectionChanged, this), |
|
|
window.onDidChangeTextEditorSelection(this.onTextEditorSelectionChanged, this), |
|
@ -142,9 +147,9 @@ export class LineTracker implements Disposable { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@debug({ args: false }) |
|
|
@debug({ args: false }) |
|
|
stop(subscriber: any) { |
|
|
|
|
|
|
|
|
unsubscribe(subscriber: unknown) { |
|
|
const subs = this._subscriptions.get(subscriber); |
|
|
const subs = this._subscriptions.get(subscriber); |
|
|
if (subs === undefined) return; |
|
|
|
|
|
|
|
|
if (subs == null) return; |
|
|
|
|
|
|
|
|
this._subscriptions.delete(subscriber); |
|
|
this._subscriptions.delete(subscriber); |
|
|
for (const sub of subs) { |
|
|
for (const sub of subs) { |
|
@ -153,14 +158,12 @@ export class LineTracker implements Disposable { |
|
|
|
|
|
|
|
|
if (this._subscriptions.size !== 0) return; |
|
|
if (this._subscriptions.size !== 0) return; |
|
|
|
|
|
|
|
|
if (this._linesChangedDebounced !== undefined) { |
|
|
|
|
|
|
|
|
if (this._linesChangedDebounced != null) { |
|
|
this._linesChangedDebounced.cancel(); |
|
|
this._linesChangedDebounced.cancel(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (this._disposable !== undefined) { |
|
|
|
|
|
this._disposable.dispose(); |
|
|
|
|
|
this._disposable = undefined; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this._disposable?.dispose(); |
|
|
|
|
|
this._disposable = undefined; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private _suspended = false; |
|
|
private _suspended = false; |
|
@ -171,8 +174,8 @@ export class LineTracker implements Disposable { |
|
|
protected onResume?(): void; |
|
|
protected onResume?(): void; |
|
|
|
|
|
|
|
|
@debug() |
|
|
@debug() |
|
|
resume(options: { force?: boolean } = {}) { |
|
|
|
|
|
if (!options.force && !this._suspended) return; |
|
|
|
|
|
|
|
|
resume(options?: { force?: boolean }) { |
|
|
|
|
|
if (!options?.force && !this._suspended) return; |
|
|
|
|
|
|
|
|
this._suspended = false; |
|
|
this._suspended = false; |
|
|
void this.onResume?.(); |
|
|
void this.onResume?.(); |
|
@ -182,8 +185,8 @@ export class LineTracker implements Disposable { |
|
|
protected onSuspend?(): void; |
|
|
protected onSuspend?(): void; |
|
|
|
|
|
|
|
|
@debug() |
|
|
@debug() |
|
|
suspend(options: { force?: boolean } = {}) { |
|
|
|
|
|
if (!options.force && this._suspended) return; |
|
|
|
|
|
|
|
|
suspend(options?: { force?: boolean }) { |
|
|
|
|
|
if (!options?.force && this._suspended) return; |
|
|
|
|
|
|
|
|
this._suspended = true; |
|
|
this._suspended = true; |
|
|
void this.onSuspend?.(); |
|
|
void this.onSuspend?.(); |
|
@ -201,11 +204,11 @@ export class LineTracker implements Disposable { |
|
|
private _linesChangedDebounced: Functions.Deferrable<(e: LinesChangeEvent) => void> | undefined; |
|
|
private _linesChangedDebounced: Functions.Deferrable<(e: LinesChangeEvent) => void> | undefined; |
|
|
|
|
|
|
|
|
private onLinesChanged(e: LinesChangeEvent) { |
|
|
private onLinesChanged(e: LinesChangeEvent) { |
|
|
if (e.selections === undefined) { |
|
|
|
|
|
|
|
|
if (e.selections == null) { |
|
|
queueMicrotask(() => { |
|
|
queueMicrotask(() => { |
|
|
if (window.activeTextEditor !== e.editor) return; |
|
|
|
|
|
|
|
|
if (e.editor !== window.activeTextEditor) return; |
|
|
|
|
|
|
|
|
if (this._linesChangedDebounced !== undefined) { |
|
|
|
|
|
|
|
|
if (this._linesChangedDebounced != null) { |
|
|
this._linesChangedDebounced.cancel(); |
|
|
this._linesChangedDebounced.cancel(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -215,10 +218,10 @@ export class LineTracker implements Disposable { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (this._linesChangedDebounced === undefined) { |
|
|
|
|
|
|
|
|
if (this._linesChangedDebounced == null) { |
|
|
this._linesChangedDebounced = Functions.debounce( |
|
|
this._linesChangedDebounced = Functions.debounce( |
|
|
(e: LinesChangeEvent) => { |
|
|
(e: LinesChangeEvent) => { |
|
|
if (window.activeTextEditor !== e.editor) return; |
|
|
|
|
|
|
|
|
if (e.editor !== window.activeTextEditor) return; |
|
|
// Make sure we are still on the same lines
|
|
|
// Make sure we are still on the same lines
|
|
|
if (!LineTracker.includes(e.selections, LineTracker.toLineSelections(e.editor?.selections))) { |
|
|
if (!LineTracker.includes(e.selections, LineTracker.toLineSelections(e.editor?.selections))) { |
|
|
return; |
|
|
return; |
|
@ -232,7 +235,7 @@ export class LineTracker implements Disposable { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// If we have no pending moves, then fire an immediate pending event, and defer the real event
|
|
|
// If we have no pending moves, then fire an immediate pending event, and defer the real event
|
|
|
if (!this._linesChangedDebounced.pending!()) { |
|
|
|
|
|
|
|
|
if (!this._linesChangedDebounced.pending?.()) { |
|
|
void this.fireLinesChanged({ ...e, pending: true }); |
|
|
void this.fireLinesChanged({ ...e, pending: true }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|