@codemirror/fold
Advanced tools
Comparing version 0.18.0 to 0.18.1
@@ -0,1 +1,15 @@ | ||
## 0.18.1 (2021-04-30) | ||
### Bug fixes | ||
The fold gutter will now properly update when the editor's language config changes. | ||
Fix an issue where the fold gutter could get out of date when changes below a given line affected the fold marker for that line. | ||
### New features | ||
The package now exports a `foldedRanges` function that can be used to query set of folded ranges in an editor state. | ||
The newly exported `foldEffect` and `unfoldEffect` state effects can be used to control the fold state directly. | ||
## 0.18.0 (2021-03-03) | ||
@@ -2,0 +16,0 @@ |
@@ -1,20 +0,87 @@ | ||
import { Extension } from '@codemirror/state'; | ||
import { Command, KeyBinding } from '@codemirror/view'; | ||
import * as _codemirror_state from '@codemirror/state'; | ||
import { EditorState, Extension } from '@codemirror/state'; | ||
import { DecorationSet, Command, KeyBinding } from '@codemirror/view'; | ||
declare type DocRange = { | ||
from: number; | ||
to: number; | ||
}; | ||
/** | ||
State effect that can be attached to a transaction to fold the | ||
given range. (You probably only need this in exceptional | ||
circumstances—usually you'll just want to let | ||
[`foldCode`](https://codemirror.net/6/docs/ref/#fold.foldCode) and the [fold | ||
gutter](https://codemirror.net/6/docs/ref/#fold.foldGutter) create the transactions.) | ||
*/ | ||
declare const foldEffect: _codemirror_state.StateEffectType<DocRange>; | ||
/** | ||
State effect that unfolds the given range (if it was folded). | ||
*/ | ||
declare const unfoldEffect: _codemirror_state.StateEffectType<DocRange>; | ||
/** | ||
Get a [range set](https://codemirror.net/6/docs/ref/#rangeset.RangeSet) containing the folded ranges | ||
in the given state. | ||
*/ | ||
declare function foldedRanges(state: EditorState): DecorationSet; | ||
/** | ||
Fold the lines that are selected, if possible. | ||
*/ | ||
declare const foldCode: Command; | ||
/** | ||
Unfold folded ranges on selected lines. | ||
*/ | ||
declare const unfoldCode: Command; | ||
/** | ||
Fold all top-level foldable ranges. | ||
*/ | ||
declare const foldAll: Command; | ||
/** | ||
Unfold all folded code. | ||
*/ | ||
declare const unfoldAll: Command; | ||
/** | ||
Default fold-related key bindings. | ||
- Ctrl-Shift-[ (Cmd-Alt-[ on macOS): [`foldCode`](https://codemirror.net/6/docs/ref/#fold.foldCode). | ||
- Ctrl-Shift-] (Cmd-Alt-] on macOS): [`unfoldCode`](https://codemirror.net/6/docs/ref/#fold.unfoldCode). | ||
- Ctrl-Alt-[: [`foldAll`](https://codemirror.net/6/docs/ref/#fold.foldAll). | ||
- Ctrl-Alt-]: [`unfoldAll`](https://codemirror.net/6/docs/ref/#fold.unfoldAll). | ||
*/ | ||
declare const foldKeymap: readonly KeyBinding[]; | ||
interface FoldConfig { | ||
/** | ||
A function that creates the DOM element used to indicate the | ||
position of folded code. When not given, the `placeholderText` | ||
option will be used instead. | ||
*/ | ||
placeholderDOM?: (() => HTMLElement) | null; | ||
/** | ||
Text to use as placeholder for folded text. Defaults to `"…"`. | ||
Will be styled with the `"cm-foldPlaceholder"` class. | ||
*/ | ||
placeholderText?: string; | ||
} | ||
/** | ||
Create an extension that configures code folding. | ||
*/ | ||
declare function codeFolding(config?: FoldConfig): Extension; | ||
interface FoldGutterConfig { | ||
/** | ||
Text used to indicate that a given line can be folded. Defaults | ||
to `"⌄"`. | ||
*/ | ||
openText?: string; | ||
/** | ||
Text used to indicate that a given line is folded. Defaults to | ||
`"›"`. | ||
*/ | ||
closedText?: string; | ||
} | ||
/** | ||
Create an extension that registers a fold gutter, which shows a | ||
fold status indicator before foldable lines (which can be clicked | ||
to fold or unfold the line). | ||
*/ | ||
declare function foldGutter(config?: FoldGutterConfig): Extension; | ||
export { codeFolding, foldAll, foldCode, foldGutter, foldKeymap, unfoldAll, unfoldCode }; | ||
export { codeFolding, foldAll, foldCode, foldEffect, foldGutter, foldKeymap, foldedRanges, unfoldAll, unfoldCode, unfoldEffect }; |
import { StateEffect, StateField, Facet, combineConfig } from '@codemirror/state'; | ||
import { Decoration, EditorView, WidgetType, ViewPlugin } from '@codemirror/view'; | ||
import { foldable } from '@codemirror/language'; | ||
import { foldable, language } from '@codemirror/language'; | ||
import { gutter, GutterMarker } from '@codemirror/gutter'; | ||
import { RangeSet } from '@codemirror/rangeset'; | ||
import { RangeSet, RangeSetBuilder } from '@codemirror/rangeset'; | ||
@@ -11,4 +11,14 @@ function mapRange(range, mapping) { | ||
} | ||
const foldEffect = StateEffect.define({ map: mapRange }); | ||
const unfoldEffect = StateEffect.define({ map: mapRange }); | ||
/** | ||
State effect that can be attached to a transaction to fold the | ||
given range. (You probably only need this in exceptional | ||
circumstances—usually you'll just want to let | ||
[`foldCode`](https://codemirror.net/6/docs/ref/#fold.foldCode) and the [fold | ||
gutter](https://codemirror.net/6/docs/ref/#fold.foldGutter) create the transactions.) | ||
*/ | ||
const foldEffect = /*@__PURE__*/StateEffect.define({ map: mapRange }); | ||
/** | ||
State effect that unfolds the given range (if it was folded). | ||
*/ | ||
const unfoldEffect = /*@__PURE__*/StateEffect.define({ map: mapRange }); | ||
function selectedLines(view) { | ||
@@ -23,3 +33,3 @@ let lines = []; | ||
} | ||
const foldState = StateField.define({ | ||
const foldState = /*@__PURE__*/StateField.define({ | ||
create() { | ||
@@ -33,6 +43,5 @@ return Decoration.none; | ||
folded = folded.update({ add: [foldWidget.range(e.value.from, e.value.to)] }); | ||
else if (e.is(unfoldEffect)) { | ||
else if (e.is(unfoldEffect)) | ||
folded = folded.update({ filter: (from, to) => e.value.from != from || e.value.to != to, | ||
filterFrom: e.value.from, filterTo: e.value.to }); | ||
} | ||
} | ||
@@ -55,2 +64,9 @@ // Clear folded ranges that cover the selection head | ||
}); | ||
/** | ||
Get a [range set](https://codemirror.net/6/docs/ref/#rangeset.RangeSet) containing the folded ranges | ||
in the given state. | ||
*/ | ||
function foldedRanges(state) { | ||
return state.field(foldState, false) || RangeSet.empty; | ||
} | ||
function foldInside(state, from, to) { | ||
@@ -74,3 +90,5 @@ var _a; | ||
} | ||
/// Fold the lines that are selected, if possible. | ||
/** | ||
Fold the lines that are selected, if possible. | ||
*/ | ||
const foldCode = view => { | ||
@@ -86,3 +104,5 @@ for (let line of selectedLines(view)) { | ||
}; | ||
/// Unfold folded ranges on selected lines. | ||
/** | ||
Unfold folded ranges on selected lines. | ||
*/ | ||
const unfoldCode = view => { | ||
@@ -105,3 +125,5 @@ if (!view.state.field(foldState, false)) | ||
} | ||
/// Fold all top-level foldable ranges. | ||
/** | ||
Fold all top-level foldable ranges. | ||
*/ | ||
const foldAll = view => { | ||
@@ -119,3 +141,5 @@ let { state } = view, effects = []; | ||
}; | ||
/// Unfold all folded code. | ||
/** | ||
Unfold all folded code. | ||
*/ | ||
const unfoldAll = view => { | ||
@@ -130,8 +154,10 @@ let field = view.state.field(foldState, false); | ||
}; | ||
/// Default fold-related key bindings. | ||
/// | ||
/// - Ctrl-Shift-[ (Cmd-Alt-[ on macOS): [`foldCode`](#fold.foldCode). | ||
/// - Ctrl-Shift-] (Cmd-Alt-] on macOS): [`unfoldCode`](#fold.unfoldCode). | ||
/// - Ctrl-Alt-[: [`foldAll`](#fold.foldAll). | ||
/// - Ctrl-Alt-]: [`unfoldAll`](#fold.unfoldAll). | ||
/** | ||
Default fold-related key bindings. | ||
- Ctrl-Shift-[ (Cmd-Alt-[ on macOS): [`foldCode`](https://codemirror.net/6/docs/ref/#fold.foldCode). | ||
- Ctrl-Shift-] (Cmd-Alt-] on macOS): [`unfoldCode`](https://codemirror.net/6/docs/ref/#fold.unfoldCode). | ||
- Ctrl-Alt-[: [`foldAll`](https://codemirror.net/6/docs/ref/#fold.foldAll). | ||
- Ctrl-Alt-]: [`unfoldAll`](https://codemirror.net/6/docs/ref/#fold.unfoldAll). | ||
*/ | ||
const foldKeymap = [ | ||
@@ -147,6 +173,8 @@ { key: "Ctrl-Shift-[", mac: "Cmd-Alt-[", run: foldCode }, | ||
}; | ||
const foldConfig = Facet.define({ | ||
const foldConfig = /*@__PURE__*/Facet.define({ | ||
combine(values) { return combineConfig(values, defaultConfig); } | ||
}); | ||
/// Create an extension that configures code folding. | ||
/** | ||
Create an extension that configures code folding. | ||
*/ | ||
function codeFolding(config) { | ||
@@ -158,3 +186,3 @@ let result = [foldState, baseTheme]; | ||
} | ||
const foldWidget = Decoration.replace({ widget: new class extends WidgetType { | ||
const foldWidget = /*@__PURE__*/Decoration.replace({ widget: /*@__PURE__*/new class extends WidgetType { | ||
ignoreEvents() { return false; } | ||
@@ -198,5 +226,7 @@ toDOM(view) { | ||
} | ||
/// Create an extension that registers a fold gutter, which shows a | ||
/// fold status indicator before foldable lines (which can be clicked | ||
/// to fold or unfold the line). | ||
/** | ||
Create an extension that registers a fold gutter, which shows a | ||
fold status indicator before foldable lines (which can be clicked | ||
to fold or unfold the line). | ||
*/ | ||
function foldGutter(config = {}) { | ||
@@ -208,33 +238,19 @@ let fullConfig = Object.assign(Object.assign({}, foldGutterDefaults), config); | ||
this.from = view.viewport.from; | ||
this.markers = RangeSet.of(this.buildMarkers(view)); | ||
this.markers = this.buildMarkers(view); | ||
} | ||
update(update) { | ||
let firstChange = -1; | ||
update.changes.iterChangedRanges(from => { if (firstChange < 0) | ||
firstChange = from; }); | ||
let foldChange = update.startState.field(foldState, false) != update.state.field(foldState, false); | ||
if (!foldChange && update.docChanged && update.view.viewport.from == this.from && firstChange > this.from) { | ||
let start = update.view.visualLineAt(firstChange).from; | ||
this.markers = this.markers.update({ | ||
filter: () => false, | ||
filterFrom: start, | ||
add: this.buildMarkers(update.view, start) | ||
}); | ||
} | ||
else if (foldChange || update.docChanged || update.viewportChanged) { | ||
this.from = update.view.viewport.from; | ||
this.markers = RangeSet.of(this.buildMarkers(update.view)); | ||
} | ||
if (update.docChanged || update.viewportChanged || | ||
update.startState.facet(language) != update.state.facet(language) || | ||
update.startState.field(foldState, false) != update.state.field(foldState, false)) | ||
this.markers = this.buildMarkers(update.view); | ||
} | ||
buildMarkers(view, from = 0) { | ||
let ranges = []; | ||
buildMarkers(view) { | ||
let builder = new RangeSetBuilder(); | ||
view.viewportLines(line => { | ||
if (line.from >= from) { | ||
let mark = foldInside(view.state, line.from, line.to) ? canUnfold | ||
: foldable(view.state, line.from, line.to) ? canFold : null; | ||
if (mark) | ||
ranges.push(mark.range(line.from)); | ||
} | ||
let mark = foldInside(view.state, line.from, line.to) ? canUnfold | ||
: foldable(view.state, line.from, line.to) ? canFold : null; | ||
if (mark) | ||
builder.add(line.from, line.from, mark); | ||
}); | ||
return ranges; | ||
return builder.finish(); | ||
} | ||
@@ -269,3 +285,3 @@ }); | ||
} | ||
const baseTheme = EditorView.baseTheme({ | ||
const baseTheme = /*@__PURE__*/EditorView.baseTheme({ | ||
".cm-foldPlaceholder": { | ||
@@ -286,2 +302,2 @@ backgroundColor: "#eee", | ||
export { codeFolding, foldAll, foldCode, foldGutter, foldKeymap, unfoldAll, unfoldCode }; | ||
export { codeFolding, foldAll, foldCode, foldEffect, foldGutter, foldKeymap, foldedRanges, unfoldAll, unfoldCode, unfoldEffect }; |
{ | ||
"name": "@codemirror/fold", | ||
"version": "0.18.0", | ||
"version": "0.18.1", | ||
"description": "Code folding for the CodeMirror code editor", | ||
"scripts": { | ||
"test": "echo 'No tests'", | ||
"prepare": "tsc -p tsconfig.local.json && rollup -c" | ||
"test": "cm-runtests", | ||
"prepare": "cm-buildhelper src/fold.ts" | ||
}, | ||
@@ -36,5 +36,3 @@ "keywords": [ | ||
"devDependencies": { | ||
"rollup": "^2.35.1", | ||
"rollup-plugin-dts": "^2.0.1", | ||
"typescript": "^4.1.3" | ||
"@codemirror/buildhelper": "^0.1.5" | ||
}, | ||
@@ -41,0 +39,0 @@ "repository": { |
Sorry, the diff of this file is not supported yet
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
1
665
2
29370
8