mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Merge pull request #100027 from matthew-haines/master
#97684 Add alt-click & actions to fold/unfold surronding regions
This commit is contained in:
commit
c17a5ca80f
|
@ -14,7 +14,7 @@ import { ScrollType, IEditorContribution } from 'vs/editor/common/editorCommon';
|
|||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, registerInstantiatedEditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType, toggleCollapseState, setCollapseStateUp } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType, setCollapseStateForRest, toggleCollapseState, setCollapseStateUp } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingDecorationProvider, foldingCollapsedIcon, foldingExpandedIcon } from './foldingDecorations';
|
||||
import { FoldingRegions, FoldingRegion } from './foldingRanges';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
|
@ -429,18 +429,34 @@ export class FoldingController extends Disposable implements IEditorContribution
|
|||
if (region && region.startLineNumber === lineNumber) {
|
||||
let isCollapsed = region.isCollapsed;
|
||||
if (iconClicked || isCollapsed) {
|
||||
let surrounding = e.event.altKey;
|
||||
let toToggle = [];
|
||||
let recursive = e.event.middleButton || e.event.shiftKey;
|
||||
if (recursive) {
|
||||
for (const r of foldingModel.getRegionsInside(region)) {
|
||||
if (r.isCollapsed === isCollapsed) {
|
||||
if (surrounding) {
|
||||
let filter = (otherRegion: FoldingRegion) => !otherRegion.containedBy(region!) && !region!.containedBy(otherRegion);
|
||||
let toMaybeToggle = foldingModel.getRegionsInside(null, filter);
|
||||
for (const r of toMaybeToggle) {
|
||||
if (r.isCollapsed) {
|
||||
toToggle.push(r);
|
||||
}
|
||||
}
|
||||
// if any surrounding regions are folded, unfold those. Otherwise, fold all surrounding
|
||||
if (toToggle.length === 0) {
|
||||
toToggle = toMaybeToggle;
|
||||
}
|
||||
}
|
||||
// when recursive, first only collapse all children. If all are already folded or there are no children, also fold parent.
|
||||
if (isCollapsed || !recursive || toToggle.length === 0) {
|
||||
toToggle.push(region);
|
||||
else {
|
||||
let recursive = e.event.middleButton || e.event.shiftKey;
|
||||
if (recursive) {
|
||||
for (const r of foldingModel.getRegionsInside(region)) {
|
||||
if (r.isCollapsed === isCollapsed) {
|
||||
toToggle.push(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
// when recursive, first only collapse all children. If all are already folded or there are no children, also fold parent.
|
||||
if (isCollapsed || !recursive || toToggle.length === 0) {
|
||||
toToggle.push(region);
|
||||
}
|
||||
}
|
||||
foldingModel.toggleCollapseState(toToggle);
|
||||
this.reveal({ lineNumber, column: 1 });
|
||||
|
@ -821,6 +837,51 @@ class UnfoldAllRegionsAction extends FoldingAction<void> {
|
|||
}
|
||||
}
|
||||
|
||||
class FoldAllRegionsExceptAction extends FoldingAction<void> {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.foldAllExcept',
|
||||
label: nls.localize('foldAllExcept.label', "Fold All Regions Except Selected"),
|
||||
alias: 'Fold All Regions Except Selected',
|
||||
precondition: CONTEXT_FOLDING_ENABLED,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.editorTextFocus,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_MINUS),
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
invoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {
|
||||
let selectedLines = this.getSelectedLines(editor);
|
||||
setCollapseStateForRest(foldingModel, true, selectedLines);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UnfoldAllRegionsExceptAction extends FoldingAction<void> {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.unfoldAllExcept',
|
||||
label: nls.localize('unfoldAllExcept.label', "Unfold All Regions Except Selected"),
|
||||
alias: 'Unfold All Regions Except Selected',
|
||||
precondition: CONTEXT_FOLDING_ENABLED,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.editorTextFocus,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_EQUAL),
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
invoke(_foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {
|
||||
let selectedLines = this.getSelectedLines(editor);
|
||||
setCollapseStateForRest(foldingModel, false, selectedLines);
|
||||
}
|
||||
}
|
||||
|
||||
class FoldAllAction extends FoldingAction<void> {
|
||||
|
||||
constructor() {
|
||||
|
@ -886,6 +947,8 @@ registerEditorAction(UnfoldAllAction);
|
|||
registerEditorAction(FoldAllBlockCommentsAction);
|
||||
registerEditorAction(FoldAllRegionsAction);
|
||||
registerEditorAction(UnfoldAllRegionsAction);
|
||||
registerEditorAction(FoldAllRegionsExceptAction);
|
||||
registerEditorAction(UnfoldAllRegionsExceptAction);
|
||||
registerEditorAction(ToggleFoldAction);
|
||||
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
|
|
|
@ -368,6 +368,21 @@ export function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: n
|
|||
foldingModel.toggleCollapseState(toToggle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Folds or unfolds all regions, except if they contain or are contained by a region of one of the blocked lines.
|
||||
* @param doCollapse Whether to collapse or expand
|
||||
* @param blockedLineNumbers the location of regions to not collapse or expand
|
||||
*/
|
||||
export function setCollapseStateForRest(foldingModel: FoldingModel, doCollapse: boolean, blockedLineNumbers: number[]): void {
|
||||
let filteredRegions: FoldingRegion[] = [];
|
||||
for (let lineNumber of blockedLineNumbers) {
|
||||
filteredRegions.push(foldingModel.getAllRegionsAtLine(lineNumber, undefined)[0]);
|
||||
}
|
||||
let filter = (region: FoldingRegion) => filteredRegions.every((filteredRegion) => !filteredRegion.containedBy(region) && !region.containedBy(filteredRegion)) && region.isCollapsed !== doCollapse;
|
||||
let toToggle = foldingModel.getRegionsInside(null, filter);
|
||||
foldingModel.toggleCollapseState(toToggle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Folds all regions for which the lines start with a given regex
|
||||
* @param foldingModel the folding model
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { FoldingModel, setCollapseStateAtLevel, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateUp } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingModel, setCollapseStateAtLevel, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateUp, setCollapseStateForRest } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
import { computeRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
|
||||
|
@ -717,6 +717,56 @@ suite('Folding Model', () => {
|
|||
|
||||
});
|
||||
|
||||
|
||||
test('setCollapseStateForRest', () => {
|
||||
let lines = [
|
||||
/* 1*/ '//#region',
|
||||
/* 2*/ '//#endregion',
|
||||
/* 3*/ 'class A {',
|
||||
/* 4*/ ' void foo() {',
|
||||
/* 5*/ ' if (true) {',
|
||||
/* 6*/ ' return;',
|
||||
/* 7*/ ' }',
|
||||
/* 8*/ '',
|
||||
/* 9*/ ' if (true) {',
|
||||
/* 10*/ ' return;',
|
||||
/* 11*/ ' }',
|
||||
/* 12*/ ' }',
|
||||
/* 13*/ '}'];
|
||||
|
||||
let textModel = createTextModel(lines.join('\n'));
|
||||
try {
|
||||
let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel));
|
||||
|
||||
let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ });
|
||||
foldingModel.update(ranges);
|
||||
|
||||
let r1 = r(1, 2, false);
|
||||
let r2 = r(3, 12, false);
|
||||
let r3 = r(4, 11, false);
|
||||
let r4 = r(5, 6, false);
|
||||
let r5 = r(9, 10, false);
|
||||
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
|
||||
|
||||
setCollapseStateForRest(foldingModel, true, [5]);
|
||||
assertFoldedRanges(foldingModel, [r1, r5], '1');
|
||||
|
||||
setCollapseStateForRest(foldingModel, false, [5]);
|
||||
assertFoldedRanges(foldingModel, [], '2');
|
||||
|
||||
setCollapseStateForRest(foldingModel, true, [1]);
|
||||
assertFoldedRanges(foldingModel, [r2, r3, r4, r5], '3');
|
||||
|
||||
setCollapseStateForRest(foldingModel, true, [3]);
|
||||
assertFoldedRanges(foldingModel, [r1, r2, r3, r4, r5], '3');
|
||||
|
||||
} finally {
|
||||
textModel.dispose();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
test('folding decoration', () => {
|
||||
let lines = [
|
||||
/* 1*/ 'class A {',
|
||||
|
|
Loading…
Reference in a new issue