Skip to content

Commit

Permalink
Add wordWrapColumn and bounded line wrapping modes. (jupyterlab#4936
Browse files Browse the repository at this point in the history
)

* Add `wordWrapColumn` property to the `editorConfig`section of jupyterlab
settings and changes `linewarp` setting to accept one of the following
string values: `off`, `on`, `wordWrapColumn`, `bounded`.

* Fix tests.
  • Loading branch information
AlbertHilb authored and blink1073 committed Jul 23, 2018
1 parent 80d2238 commit 81133a1
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 30 deletions.
16 changes: 13 additions & 3 deletions packages/codeeditor/src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,9 +567,13 @@ export namespace CodeEditor {
lineNumbers: boolean;

/**
* Set to false for horizontal scrolling.
* Control the line wrapping of the editor. Possible values are:
* - "off", lines will never wrap.
* - "on", lines will wrap at the viewport border.
* - "wordWrapColumn", lines will wrap at `wordWrapColumn`.
* - "bounded", lines will wrap at minimum between viewport width and wordWrapColumn.
*/
lineWrap: boolean;
lineWrap: 'off' | 'on' | 'wordWrapColumn' | 'bounded';

/**
* Whether the editor is read-only.
Expand All @@ -595,6 +599,11 @@ export namespace CodeEditor {
* Whether to automatically close brackets after opening them.
*/
autoClosingBrackets: boolean;

/**
* The column where to break text line.
*/
wordWrapColumn: number;
}

/**
Expand All @@ -605,7 +614,8 @@ export namespace CodeEditor {
fontSize: null,
lineHeight: null,
lineNumbers: false,
lineWrap: true,
lineWrap: 'on',
wordWrapColumn: 80,
readOnly: false,
tabSize: 4,
insertSpaces: true,
Expand Down
34 changes: 30 additions & 4 deletions packages/codemirror/src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ export class CodeMirrorEditor implements CodeEditor.IEditor {
// Don't bother setting the option if it is already the same.
if (this._config[option] !== value) {
this._config[option] = value;
Private.setOption(this.editor, option, value);
Private.setOption(this.editor, option, value, this._config);
}
}

Expand Down Expand Up @@ -1132,6 +1132,7 @@ namespace Private {
insertSpaces,
lineHeight,
lineWrap,
wordWrapColumn,
tabSize,
readOnly,
...otherOptions
Expand All @@ -1140,7 +1141,7 @@ namespace Private {
autoCloseBrackets: autoClosingBrackets,
indentUnit: tabSize,
indentWithTabs: !insertSpaces,
lineWrapping: lineWrap,
lineWrapping: lineWrap === 'off' ? false : true,
readOnly,
...otherOptions
};
Expand All @@ -1157,6 +1158,14 @@ namespace Private {
if (readOnly) {
el.classList.add(READ_ONLY_CLASS);
}
if (lineWrap === 'wordWrapColumn') {
const lines = el.querySelector('.CodeMirror-lines') as HTMLDivElement;
lines.style.width = `${wordWrapColumn}ch`;
}
if (lineWrap === 'bounded') {
const lines = el.querySelector('.CodeMirror-lines') as HTMLDivElement;
lines.style.maxWidth = `${wordWrapColumn}ch`;
}
host.appendChild(el);
}, bareConfig);
}
Expand Down Expand Up @@ -1236,12 +1245,29 @@ namespace Private {
export function setOption<K extends keyof CodeMirrorEditor.IConfig>(
editor: CodeMirror.Editor,
option: K,
value: CodeMirrorEditor.IConfig[K]
value: CodeMirrorEditor.IConfig[K],
config: CodeMirrorEditor.IConfig
): void {
let el = editor.getWrapperElement();
switch (option) {
case 'lineWrap':
editor.setOption('lineWrapping', value);
const lineWrapping = value === 'off' ? false : true;
const lines = el.querySelector('.CodeMirror-lines') as HTMLDivElement;
const maxWidth =
value === 'bounded' ? `${config.wordWrapColumn}ch` : null;
const width =
value === 'wordWrapColumn' ? `${config.wordWrapColumn}ch` : null;
lines.style.maxWidth = maxWidth;
lines.style.width = width;
editor.setOption('lineWrapping', lineWrapping);
break;
case 'wordWrapColumn':
const { lineWrap } = config;
if (lineWrap === 'wordWrapColumn' || lineWrap === 'bounded') {
const lines = el.querySelector('.CodeMirror-lines') as HTMLDivElement;
const prop = lineWrap === 'wordWrapColumn' ? 'width' : 'maxWidth';
lines.style[prop] = `${value}ch`;
}
break;
case 'tabSize':
editor.setOption('indentUnit', value);
Expand Down
11 changes: 8 additions & 3 deletions packages/fileeditor-extension/schema/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"type": "boolean"
},
"lineWrap": {
"type": "boolean"
"type": "string",
"enum": ["off", "on", "wordWrapColumn", "bounded"]
},
"matchBrackets": {
"type": "boolean"
Expand All @@ -37,6 +38,9 @@
},
"tabSize": {
"type": "number"
},
"wordWrapColumn": {
"type": "integer"
}
},
"additionalProperties": false,
Expand All @@ -55,11 +59,12 @@
"fontSize": null,
"lineHeight": null,
"lineNumbers": true,
"lineWrap": true,
"lineWrap": "on",
"matchBrackets": true,
"readOnly": false,
"insertSpaces": true,
"tabSize": 4
"tabSize": 4,
"wordWrapColumn": 80
}
}
},
Expand Down
20 changes: 14 additions & 6 deletions packages/fileeditor-extension/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,17 +252,23 @@ function activate(
label: 'Line Numbers'
});

type wrappingMode = 'on' | 'off' | 'wordWrapColumn' | 'bounded';

commands.addCommand(CommandIDs.lineWrap, {
execute: () => {
config.lineWrap = !config.lineWrap;
execute: args => {
const lineWrap = (args['mode'] as wrappingMode) || 'off';
config.lineWrap = lineWrap;
return settingRegistry
.set(id, 'editorConfig', config)
.catch((reason: Error) => {
console.error(`Failed to set ${id}: ${reason.message}`);
});
},
isEnabled,
isToggled: () => config.lineWrap,
isToggled: args => {
const lineWrap = (args['mode'] as wrappingMode) || 'off';
return config.lineWrap === lineWrap;
},
label: 'Word Wrap'
});

Expand Down Expand Up @@ -534,16 +540,18 @@ function activate(
widget.content.editor.setOption('lineNumbers', lineNumbers);
},
toggleWordWrap: widget => {
const wordWrap = !widget.content.editor.getOption('lineWrap');
widget.content.editor.setOption('lineWrap', wordWrap);
const oldValue = widget.content.editor.getOption('lineWrap');
const newValue = oldValue === 'off' ? 'on' : 'off';
widget.content.editor.setOption('lineWrap', newValue);
},
toggleMatchBrackets: widget => {
const matchBrackets = !widget.content.editor.getOption('matchBrackets');
widget.content.editor.setOption('matchBrackets', matchBrackets);
},
lineNumbersToggled: widget =>
widget.content.editor.getOption('lineNumbers'),
wordWrapToggled: widget => widget.content.editor.getOption('lineWrap'),
wordWrapToggled: widget =>
widget.content.editor.getOption('lineWrap') !== 'off',
matchBracketsToggled: widget =>
widget.content.editor.getOption('matchBrackets')
} as IViewMenu.IEditorViewer<IDocumentWidget<FileEditor>>);
Expand Down
21 changes: 14 additions & 7 deletions packages/notebook-extension/schema/tracker.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"type": "boolean"
},
"lineWrap": {
"type": "boolean"
"type": "string",
"enum": ["off", "on", "wordWrapColumn", "bounded"]
},
"matchBrackets": {
"type": "boolean"
Expand All @@ -37,6 +38,9 @@
},
"tabSize": {
"type": "number"
},
"wordWrapColumn": {
"type": "integer"
}
},
"additionalProperties": false,
Expand All @@ -54,11 +58,12 @@
"fontSize": null,
"lineHeight": null,
"lineNumbers": false,
"lineWrap": false,
"lineWrap": "off",
"matchBrackets": true,
"readOnly": false,
"insertSpaces": true,
"tabSize": 4
"tabSize": 4,
"wordWrapColumn": 80
}
},
"markdownCellConfig": {
Expand All @@ -71,11 +76,12 @@
"fontSize": null,
"lineHeight": null,
"lineNumbers": false,
"lineWrap": true,
"lineWrap": "on",
"matchBrackets": false,
"readOnly": false,
"insertSpaces": true,
"tabSize": 4
"tabSize": 4,
"wordWrapColumn": 80
}
},
"rawCellConfig": {
Expand All @@ -88,11 +94,12 @@
"fontSize": null,
"lineHeight": null,
"lineNumbers": false,
"lineWrap": true,
"lineWrap": "on",
"matchBrackets": false,
"readOnly": false,
"insertSpaces": true,
"tabSize": 4
"tabSize": 4,
"wordWrapColumn": 80
}
}
},
Expand Down
6 changes: 3 additions & 3 deletions packages/notebook/src/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -646,19 +646,19 @@ export namespace StaticNotebook {
export const defaultEditorConfig: IEditorConfig = {
code: {
...CodeEditor.defaultConfig,
lineWrap: false,
lineWrap: 'off',
matchBrackets: true,
autoClosingBrackets: true
},
markdown: {
...CodeEditor.defaultConfig,
lineWrap: true,
lineWrap: 'on',
matchBrackets: false,
autoClosingBrackets: false
},
raw: {
...CodeEditor.defaultConfig,
lineWrap: true,
lineWrap: 'on',
matchBrackets: false,
autoClosingBrackets: false
}
Expand Down
6 changes: 3 additions & 3 deletions tests/test-codemirror/src/editor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ describe('CodeMirrorEditor', () => {
});

it('should get whether horizontally scrolling should be used', () => {
expect(editor.getOption('lineWrap')).to.be(true);
expect(editor.getOption('lineWrap')).to.be('on');
});

it('should get whether the editor is readonly', () => {
Expand All @@ -146,8 +146,8 @@ describe('CodeMirrorEditor', () => {
});

it('should set whether horizontally scrolling should be used', () => {
editor.setOption('lineWrap', false);
expect(editor.getOption('lineWrap')).to.be(false);
editor.setOption('lineWrap', 'off');
expect(editor.getOption('lineWrap')).to.be('off');
});

it('should set whether the editor is readonly', () => {
Expand Down
2 changes: 1 addition & 1 deletion tests/test-codemirror/src/factory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('CodeMirrorEditorFactory', () => {

const options: Partial<CodeMirrorEditor.IConfig> = {
lineNumbers: false,
lineWrap: true,
lineWrap: 'on',
extraKeys: {
'Ctrl-Tab': 'indentAuto'
}
Expand Down

0 comments on commit 81133a1

Please sign in to comment.