Add a setting option to specify when to automatically show or hide the wrap-guide

This commit is contained in:
Trigan2025 2023-10-21 01:07:58 +02:00
parent 6f1c7720a2
commit 05ec5a7c26
4 changed files with 631 additions and 275 deletions

View File

@ -6,20 +6,25 @@ module.exports = {
this.subscriptions = new CompositeDisposable();
this.wrapGuides = new Map();
this.subscriptions.add(atom.workspace.observeTextEditors(editor => {
if (this.wrapGuides.has(editor)) { return; }
this.when = atom.config.get("wrap-guide.showWrapGuide");
this.subscriptions.add(atom.config.onDidChange('wrap-guide.showWrapGuide', (args) => {
this.when = args.newValue;
atom.workspace.getTextEditors().forEach(async (editor) => {
await this.wrapGuides.get(editor).setWhen(this.when);
});
}));
this.subscriptions.add(atom.workspace.observeTextEditors((editor) => {
if (this.wrapGuides.has(editor)) return;
const editorElement = atom.views.getView(editor);
const wrapGuideElement = new WrapGuideElement(editor, editorElement);
const wrapGuideElement = new WrapGuideElement(editor, editorElement, this.when);
this.wrapGuides.set(editor, wrapGuideElement);
this.subscriptions.add(editor.onDidDestroy(() => {
this.wrapGuides.get(editor).destroy();
this.wrapGuides.delete(editor);
})
);
})
);
}));
}));
},
deactivate() {

View File

@ -1,20 +1,47 @@
const {CompositeDisposable} = require('atom');
module.exports = class WrapGuideElement {
constructor(editor, editorElement) {
#_when = null;
#_shouldShow = null;
constructor(editor, editorElement, when) {
this.editor = editor;
this.editorElement = editorElement;
this.subscriptions = new CompositeDisposable();
this.configSubscriptions = new CompositeDisposable();
this.softWrapAPLLsubscriptions = null;
this.element = document.createElement('div');
this.element.setAttribute('is', 'wrap-guide');
this.element.classList.add('wrap-guide-container');
this.attachToLines();
this.handleEvents();
this.updateGuide();
this.setWhen(when);
this.element.updateGuide = this.updateGuide.bind(this);
this.element.getDefaultColumn = this.getDefaultColumn.bind(this);
this.element.updateGuide = (async () => await this.updateGuide()).bind(this);
this.element.getDefaultColumn = (async () => await this.getDefaultColumn()).bind(this);
}
get shouldShow() { return this.#_shouldShow; }
get when() { return this.#_when; }
setWhen(when) {
if (when == this.when) return;
this.#_when = when;
this.updateWhen();
}
async updateWhen() {
switch (this.when) {
case "atPreferredLineLength":
this.#_shouldShow = this.editor.isSoftWrapped() && atom.config.get('editor.softWrapAtPreferredLineLength', {scope: this.editor.getRootScopeDescriptor()});
break;
case "wrapping":
this.#_shouldShow = this.editor.isSoftWrapped();
break;
default: // "always"
this.#_shouldShow = true;
break;
}
await this.updateGuide();
}
attachToLines() {
@ -23,86 +50,94 @@ module.exports = class WrapGuideElement {
}
handleEvents() {
const updateGuideCallback = () => this.updateGuide();
const updateGuideCallback = async () => await this.updateGuide();
this.handleConfigEvents();
this.subscriptions.add(atom.config.onDidChange('editor.fontSize', () => {
this.subscriptions.add(this.editor.onDidChangeSoftWrapped(async (wrapped) => {
if (this.when === null) return;
await this.updateWhen();
}));
this.subscriptions.add(atom.config.onDidChange('editor.fontSize', async () => {
// Wait for editor to finish updating before updating wrap guide
// TODO: Use async/await once this file is converted to JS
this.editorElement.getComponent().getNextUpdatePromise().then(() => updateGuideCallback());
})
);
await this.editorElement.getComponent().getNextUpdatePromise();
updateGuideCallback();
}));
this.subscriptions.add(this.editorElement.onDidChangeScrollLeft(updateGuideCallback));
this.subscriptions.add(this.editor.onDidChangePath(updateGuideCallback));
this.subscriptions.add(this.editor.onDidChangeGrammar(() => {
this.subscriptions.add(this.editor.onDidChangeGrammar(async () => {
this.configSubscriptions.dispose();
this.handleConfigEvents();
updateGuideCallback();
})
);
await this.updateWhen();
}));
this.subscriptions.add(this.editor.onDidDestroy(() => {
this.subscriptions.dispose();
if (this.softWrapAPLLsubscriptions) this.softWrapAPLLsubscriptions.dispose();
this.configSubscriptions.dispose();
})
);
}));
this.subscriptions.add(this.editorElement.onDidAttach(() => {
this.subscriptions.add(this.editorElement.onDidAttach(async () => {
this.attachToLines();
updateGuideCallback();
})
);
await updateGuideCallback();
}));
}
handleConfigEvents() {
const {uniqueAscending} = require('./main');
const updatePreferredLineLengthCallback = args => {
if (this.softWrapAPLLsubscriptions) this.softWrapAPLLsubscriptions.dispose();
this.softWrapAPLLsubscriptions = new CompositeDisposable();
this.softWrapAPLLsubscriptions.add(atom.config.onDidChange('editor.softWrapAtPreferredLineLength',
{scope: this.editor.getRootScopeDescriptor()}, async ({newValue}) => {
if (this.when === null) return;
await this.updateWhen();
}));
const updatePreferredLineLengthCallback = async (args) => {
// ensure that the right-most wrap guide is the preferredLineLength
let columns = atom.config.get('wrap-guide.columns', {scope: this.editor.getRootScopeDescriptor()});
if (columns.length > 0) {
columns[columns.length - 1] = args.newValue;
columns = uniqueAscending(Array.from(columns).filter((i) => i <= args.newValue));
atom.config.set('wrap-guide.columns', columns,
{scopeSelector: `.${this.editor.getGrammar().scopeName}`});
{scopeSelector: this.editor.getRootScopeDescriptor()});
}
return this.updateGuide();
return await this.updateGuide();
};
this.configSubscriptions.add(atom.config.onDidChange(
'editor.preferredLineLength',
{scope: this.editor.getRootScopeDescriptor()},
updatePreferredLineLengthCallback
)
);
));
const updateGuideCallback = () => this.updateGuide();
const updateGuideCallback = async () => await this.updateGuide();
this.configSubscriptions.add(atom.config.onDidChange(
'wrap-guide.enabled',
{scope: this.editor.getRootScopeDescriptor()},
updateGuideCallback
)
);
));
const updateGuidesCallback = args => {
const updateGuidesCallback = async (args) => {
// ensure that multiple guides stay sorted in ascending order
const columns = uniqueAscending(args.newValue);
if (columns != null ? columns.length : undefined) {
atom.config.set('wrap-guide.columns', columns);
if (atom.config.get('wrap-guide.modifyPreferredLineLength')) {
atom.config.set('editor.preferredLineLength', columns[columns.length - 1],
{scopeSelector: `.${this.editor.getGrammar().scopeName}`});
{scopeSelector: this.editor.getRootScopeDescriptor()});
}
return this.updateGuide();
return await this.updateGuide();
}
};
return this.configSubscriptions.add(atom.config.onDidChange(
'wrap-guide.columns',
{scope: this.editor.getRootScopeDescriptor()},
updateGuidesCallback
)
);
));
}
getDefaultColumn() {
@ -130,15 +165,14 @@ module.exports = class WrapGuideElement {
}
updateGuide() {
if (this.isEnabled()) {
if (this.isEnabled())
return this.updateGuides();
} else {
return this.hide();
}
else return this.hide();
}
updateGuides() {
this.removeGuides();
if (!this.shouldShow) return this.hide();
this.appendGuides();
if (this.element.children.length) {
return this.show();
@ -150,6 +184,7 @@ module.exports = class WrapGuideElement {
destroy() {
this.element.remove();
this.subscriptions.dispose();
if (this.softWrapAPLLsubscriptions) this.softWrapAPLLsubscriptions.dispose();
return this.configSubscriptions.dispose();
}

View File

@ -1,6 +1,6 @@
{
"name": "wrap-guide",
"version": "0.41.0",
"version": "0.41.1",
"main": "./lib/main",
"description": "Displays a vertical line at the 80th character in the editor.\nThis packages uses the config value of `editor.preferredLineLength` when set.",
"license": "MIT",
@ -25,6 +25,25 @@
"enabled": {
"default": true,
"type": "boolean"
},
"showWrapGuide": {
"type": "string",
"description": "Choose when to show the wrap guide.",
"enum": [
{
"value": "always",
"description": "Always"
},
{
"value": "wrapping",
"description": "If wrapping"
},
{
"value": "atPreferredLineLength",
"description": "If wrapping at preferred line length"
}
],
"default": "atPreferredLineLength"
}
}
}

View File

@ -10,145 +10,131 @@ const {uniqueAscending} = require('../lib/main');
describe("WrapGuideElement", function() {
let [editor, editorElement, wrapGuide, workspaceElement] = [];
beforeEach(function() {
workspaceElement = atom.views.getView(atom.workspace);
workspaceElement.style.height = "200px";
workspaceElement.style.width = "1500px";
describe("When always shown", function() {
beforeEach(function() {
atom.config.set('wrap-guide.showWrapGuide', 'always');
workspaceElement = atom.views.getView(atom.workspace);
workspaceElement.style.height = "200px";
workspaceElement.style.width = "1500px";
jasmine.attachToDOM(workspaceElement);
jasmine.attachToDOM(workspaceElement);
waitsForPromise(() => atom.packages.activatePackage('wrap-guide'));
waitsForPromise(() => atom.packages.activatePackage('wrap-guide'));
waitsForPromise(() => atom.packages.activatePackage('language-javascript'));
waitsForPromise(() => atom.packages.activatePackage('language-javascript'));
waitsForPromise(() => atom.packages.activatePackage('language-coffee-script'));
waitsForPromise(() => atom.packages.activatePackage('language-coffee-script'));
waitsForPromise(() => atom.workspace.open('sample.js'));
runs(function() {
editor = atom.workspace.getActiveTextEditor();
editorElement = editor.getElement();
wrapGuide = editorElement.querySelector(".wrap-guide-container");
});
});
describe(".activate", function() {
const getWrapGuides = function() {
const wrapGuides = [];
atom.workspace.getTextEditors().forEach(function(editor) {
const guides = editor.getElement().querySelectorAll(".wrap-guide");
if (guides) { return wrapGuides.push(guides); }
});
return wrapGuides;
};
it("appends a wrap guide to all existing and new editors", function() {
expect(atom.workspace.getTextEditors().length).toBe(1);
expect(getWrapGuides().length).toBe(1);
expect(getLeftPosition(getWrapGuides()[0][0])).toBeGreaterThan(0);
atom.workspace.getActivePane().splitRight({copyActiveItem: true});
expect(atom.workspace.getTextEditors().length).toBe(2);
expect(getWrapGuides().length).toBe(2);
expect(getLeftPosition(getWrapGuides()[0][0])).toBeGreaterThan(0);
expect(getLeftPosition(getWrapGuides()[1][0])).toBeGreaterThan(0);
});
it("positions the guide at the configured column", function() {
const width = editor.getDefaultCharWidth() * wrapGuide.getDefaultColumn();
expect(width).toBeGreaterThan(0);
expect(Math.abs(getLeftPosition(wrapGuide.firstChild) - width)).toBeLessThan(1);
expect(wrapGuide).toBeVisible();
});
it("appends multiple wrap guides to all existing and new editors", function() {
const columns = [10, 20, 30];
atom.config.set("wrap-guide.columns", columns);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
waitsForPromise(() => atom.workspace.open('sample.js'));
runs(function() {
editor = atom.workspace.getActiveTextEditor();
editorElement = editor.getElement();
wrapGuide = editorElement.querySelector(".wrap-guide-container");
});
});
describe(".activate", function() {
const getWrapGuides = function() {
const wrapGuides = [];
atom.workspace.getTextEditors().forEach(function(editor) {
const guides = editor.getElement().querySelectorAll(".wrap-guide");
if (guides) { return wrapGuides.push(guides); }
});
return wrapGuides;
};
it("appends a wrap guide to all existing and new editors", function() {
expect(atom.workspace.getTextEditors().length).toBe(1);
expect(getWrapGuides().length).toBe(1);
const positions = getLeftPositions(getWrapGuides()[0]);
expect(positions.length).toBe(columns.length);
expect(positions[0]).toBeGreaterThan(0);
expect(positions[1]).toBeGreaterThan(positions[0]);
expect(positions[2]).toBeGreaterThan(positions[1]);
expect(getLeftPosition(getWrapGuides()[0][0])).toBeGreaterThan(0);
atom.workspace.getActivePane().splitRight({copyActiveItem: true});
expect(atom.workspace.getTextEditors().length).toBe(2);
expect(getWrapGuides().length).toBe(2);
const pane1_positions = getLeftPositions(getWrapGuides()[0]);
expect(pane1_positions.length).toBe(columns.length);
expect(pane1_positions[0]).toBeGreaterThan(0);
expect(pane1_positions[1]).toBeGreaterThan(pane1_positions[0]);
expect(pane1_positions[2]).toBeGreaterThan(pane1_positions[1]);
const pane2_positions = getLeftPositions(getWrapGuides()[1]);
expect(pane2_positions.length).toBe(pane1_positions.length);
expect(pane2_positions[0]).toBe(pane1_positions[0]);
expect(pane2_positions[1]).toBe(pane1_positions[1]);
expect(pane2_positions[2]).toBe(pane1_positions[2]);
expect(getLeftPosition(getWrapGuides()[0][0])).toBeGreaterThan(0);
expect(getLeftPosition(getWrapGuides()[1][0])).toBeGreaterThan(0);
});
});
it("positions multiple guides at the configured columns", function() {
// Previously used CoffeeScript below:
/**
it("positions the guide at the configured column", function() {
// const width = editor.getDefaultCharWidth() * wrapGuide.getDefaultColumn();
waitsForPromise(() => wrapGuide.getDefaultColumn().then((column) => {
const width = column * editor.getDefaultCharWidth();
expect(width).toBeGreaterThan(0);
expect(Math.abs(getLeftPosition(wrapGuide.firstChild) - width)).toBeLessThan(1);
expect(wrapGuide).toBeVisible();
}));
});
it("appends multiple wrap guides to all existing and new editors", function() {
const columns = [10, 20, 30];
atom.config.set("wrap-guide.columns", columns);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
expect(atom.workspace.getTextEditors().length).toBe(1);
expect(getWrapGuides().length).toBe(1);
const positions = getLeftPositions(getWrapGuides()[0]);
expect(positions.length).toBe(columns.length);
expect(positions[0]).toBeGreaterThan(0);
expect(positions[1]).toBeGreaterThan(positions[0]);
expect(positions[2]).toBeGreaterThan(positions[1]);
atom.workspace.getActivePane().splitRight({copyActiveItem: true});
expect(atom.workspace.getTextEditors().length).toBe(2);
expect(getWrapGuides().length).toBe(2);
const pane1_positions = getLeftPositions(getWrapGuides()[0]);
expect(pane1_positions.length).toBe(columns.length);
expect(pane1_positions[0]).toBeGreaterThan(0);
expect(pane1_positions[1]).toBeGreaterThan(pane1_positions[0]);
expect(pane1_positions[2]).toBeGreaterThan(pane1_positions[1]);
const pane2_positions = getLeftPositions(getWrapGuides()[1]);
expect(pane2_positions.length).toBe(pane1_positions.length);
expect(pane2_positions[0]).toBe(pane1_positions[0]);
expect(pane2_positions[1]).toBe(pane1_positions[1]);
expect(pane2_positions[2]).toBe(pane1_positions[2]);
});
});
it("positions multiple guides at the configured columns", function() {
// Previously used CoffeeScript below:
/**
* columnCount = 5
* columns = (c * 10 for c in [1..columnCount])
*/
const columnCount = 5;
let columns = [];
const columnCount = 5;
let columns = [];
for (let i = 0; i < columnCount; i++) {
columns.push(i * 10);
}
atom.config.set("wrap-guide.columns", columns);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
const positions = getLeftPositions(getWrapGuides()[0]);
expect(positions.length).toBe(columnCount);
expect(wrapGuide.children.length).toBe(columnCount);
for (let i of Array.from(columnCount - 1)) {
const width = editor.getDefaultCharWidth() * columns[i];
expect(width).toBeGreaterThan(0);
expect(Math.abs(getLeftPosition(wrapGuide.children[i]) - width)).toBeLessThan(1);
for (let i = 0; i < columnCount; i++) {
columns.push(i * 10);
}
expect(wrapGuide).toBeVisible();
});
});
});
describe("when the font size changes", function() {
it("updates the wrap guide position", function() {
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
const fontSize = atom.config.get("editor.fontSize");
atom.config.set("editor.fontSize", fontSize + 10);
atom.config.set("wrap-guide.columns", columns);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
const positions = getLeftPositions(getWrapGuides()[0]);
expect(positions.length).toBe(columnCount);
expect(wrapGuide.children.length).toBe(columnCount);
runs(function() {
expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial);
expect(wrapGuide.firstChild).toBeVisible();
for (let i of Array.from(columnCount - 1)) {
const width = editor.getDefaultCharWidth() * columns[i];
expect(width).toBeGreaterThan(0);
expect(Math.abs(getLeftPosition(wrapGuide.children[i]) - width)).toBeLessThan(1);
}
expect(wrapGuide).toBeVisible();
});
});
});
it("updates the wrap guide position for hidden editors when they become visible", function() {
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
waitsForPromise(() => atom.workspace.open());
runs(function() {
describe("when the font size changes", function() {
it("updates the wrap guide position", function() {
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
const fontSize = atom.config.get("editor.fontSize");
atom.config.set("editor.fontSize", fontSize + 10);
atom.workspace.getActivePane().activatePreviousItem();
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
@ -157,171 +143,482 @@ describe("WrapGuideElement", function() {
expect(wrapGuide.firstChild).toBeVisible();
});
});
it("updates the wrap guide position for hidden editors when they become visible", function() {
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
waitsForPromise(() => atom.workspace.open());
runs(function() {
const fontSize = atom.config.get("editor.fontSize");
atom.config.set("editor.fontSize", fontSize + 10);
atom.workspace.getActivePane().activatePreviousItem();
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial);
expect(wrapGuide.firstChild).toBeVisible();
});
});
});
});
});
describe("when the column config changes", () => it("updates the wrap guide position", function() {
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
const column = atom.config.get("editor.preferredLineLength");
atom.config.set("editor.preferredLineLength", column + 10);
expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial);
expect(wrapGuide).toBeVisible();
}));
describe("when the column config changes", () => it("updates the wrap guide position", function() {
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
const column = atom.config.get("editor.preferredLineLength");
atom.config.set("editor.preferredLineLength", column + 10);
expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial);
expect(wrapGuide).toBeVisible();
}));
describe("when the preferredLineLength changes", () => it("updates the wrap guide positions", function() {
const initial = [10, 15, 20, 30];
atom.config.set('wrap-guide.columns', initial,
describe("when the preferredLineLength changes", () => it("updates the wrap guide positions", function() {
const initial = [10, 15, 20, 30];
atom.config.set('wrap-guide.columns', initial,
{scopeSelector: `.${editor.getGrammar().scopeName}`});
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
atom.config.set('editor.preferredLineLength', 15,
runs(function() {
atom.config.set('editor.preferredLineLength', 15,
{scopeSelector: `.${editor.getGrammar().scopeName}`});
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
const columns = atom.config.get('wrap-guide.columns', {scope: editor.getRootScopeDescriptor()});
expect(columns.length).toBe(2);
expect(columns[0]).toBe(10);
expect(columns[1]).toBe(15);
runs(function() {
const columns = atom.config.get('wrap-guide.columns', {scope: editor.getRootScopeDescriptor()});
expect(columns.length).toBe(2);
expect(columns[0]).toBe(10);
expect(columns[1]).toBe(15);
});
});
}));
describe("when the columns config changes", function() {
it("updates the wrap guide positions", function() {
const initial = getLeftPositions(wrapGuide.children);
expect(initial.length).toBe(1);
expect(initial[0]).toBeGreaterThan(0);
const columns = [10, 20, 30];
atom.config.set("wrap-guide.columns", columns);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
const positions = getLeftPositions(wrapGuide.children);
expect(positions.length).toBe(columns.length);
expect(positions[0]).toBeGreaterThan(0);
expect(positions[1]).toBeGreaterThan(positions[0]);
expect(positions[2]).toBeGreaterThan(positions[1]);
expect(wrapGuide).toBeVisible();
});
});
it("updates the preferredLineLength", function() {
const initial = atom.config.get('editor.preferredLineLength', {scope: editor.getRootScopeDescriptor()});
atom.config.set("wrap-guide.columns", [initial, initial + 10]);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
const length = atom.config.get('editor.preferredLineLength', {scope: editor.getRootScopeDescriptor()});
expect(length).toBe(initial + 10);
});
});
it("keeps guide positions unique and in ascending order", function() {
const initial = getLeftPositions(wrapGuide.children);
expect(initial.length).toBe(1);
expect(initial[0]).toBeGreaterThan(0);
const reverseColumns = [30, 20, 10];
const columns = [reverseColumns[reverseColumns.length - 1], ...reverseColumns, reverseColumns[0]];
const uniqueColumns = uniqueAscending(columns);
expect(uniqueColumns.length).toBe(3);
expect(uniqueColumns[0]).toBeGreaterThan(0);
expect(uniqueColumns[1]).toBeGreaterThan(uniqueColumns[0]);
expect(uniqueColumns[2]).toBeGreaterThan(uniqueColumns[1]);
atom.config.set("wrap-guide.columns", columns);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
const positions = getLeftPositions(wrapGuide.children);
expect(positions.length).toBe(uniqueColumns.length);
expect(positions[0]).toBeGreaterThan(0);
expect(positions[1]).toBeGreaterThan(positions[0]);
expect(positions[2]).toBeGreaterThan(positions[1]);
expect(wrapGuide).toBeVisible();
});
});
it("leaves alone preferredLineLength if modifyPreferredLineLength is false", () => {
const initial = atom.config.get("editor.preferredLineLength", { scope: editor.getRootScopeDescriptor() });
atom.config.set("wrap-guide.modifyPreferredLineLength", false);
atom.config.set("wrap-guide.columns", [ initial, initial + 10]);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(() => {
const length = atom.config.get("editor.preferredLineLength", { scope: editor.getRootScopeDescriptor() });
expect(length).toBe(initial);
});
});
});
}));
describe("when the columns config changes", function() {
it("updates the wrap guide positions", function() {
const initial = getLeftPositions(wrapGuide.children);
expect(initial.length).toBe(1);
expect(initial[0]).toBeGreaterThan(0);
describe("when the editor's scroll left changes", () => it("updates the wrap guide position to a relative position on screen", function() {
editor.setText("a long line which causes the editor to scroll");
editorElement.style.width = "100px";
const columns = [10, 20, 30];
atom.config.set("wrap-guide.columns", columns);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
waitsFor(() => editorElement.component.getMaxScrollLeft() > 10);
runs(function() {
const positions = getLeftPositions(wrapGuide.children);
expect(positions.length).toBe(columns.length);
expect(positions[0]).toBeGreaterThan(0);
expect(positions[1]).toBeGreaterThan(positions[0]);
expect(positions[2]).toBeGreaterThan(positions[1]);
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
editorElement.setScrollLeft(10);
expect(getLeftPosition(wrapGuide.firstChild)).toBe(initial - 10);
expect(wrapGuide.firstChild).toBeVisible();
});
}));
describe("when the editor's grammar changes", function() {
it("updates the wrap guide position", function() {
atom.config.set('editor.preferredLineLength', 20, {scopeSelector: '.source.js'});
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
expect(wrapGuide).toBeVisible();
editor.setGrammar(atom.grammars.grammarForScopeName('text.plain.null-grammar'));
expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial);
expect(wrapGuide).toBeVisible();
});
});
it("updates the preferredLineLength", function() {
const initial = atom.config.get('editor.preferredLineLength', {scope: editor.getRootScopeDescriptor()});
atom.config.set("wrap-guide.columns", [initial, initial + 10]);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
const length = atom.config.get('editor.preferredLineLength', {scope: editor.getRootScopeDescriptor()});
expect(length).toBe(initial + 10);
it('listens for preferredLineLength updates for the new grammar', function() {
editor.setGrammar(atom.grammars.grammarForScopeName('source.coffee'));
const initial = getLeftPosition(wrapGuide.firstChild);
atom.config.set('editor.preferredLineLength', 20, {scopeSelector: '.source.coffee'});
expect(getLeftPosition(wrapGuide.firstChild)).toBeLessThan(initial);
});
});
it("keeps guide positions unique and in ascending order", function() {
const initial = getLeftPositions(wrapGuide.children);
expect(initial.length).toBe(1);
expect(initial[0]).toBeGreaterThan(0);
const reverseColumns = [30, 20, 10];
const columns = [reverseColumns[reverseColumns.length - 1], ...reverseColumns, reverseColumns[0]];
const uniqueColumns = uniqueAscending(columns);
expect(uniqueColumns.length).toBe(3);
expect(uniqueColumns[0]).toBeGreaterThan(0);
expect(uniqueColumns[1]).toBeGreaterThan(uniqueColumns[0]);
expect(uniqueColumns[2]).toBeGreaterThan(uniqueColumns[1]);
atom.config.set("wrap-guide.columns", columns);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
runs(function() {
const positions = getLeftPositions(wrapGuide.children);
expect(positions.length).toBe(uniqueColumns.length);
expect(positions[0]).toBeGreaterThan(0);
expect(positions[1]).toBeGreaterThan(positions[0]);
expect(positions[2]).toBeGreaterThan(positions[1]);
it('listens for wrap-guide.enabled updates for the new grammar', function() {
editor.setGrammar(atom.grammars.grammarForScopeName('source.coffee'));
expect(wrapGuide).toBeVisible();
atom.config.set('wrap-guide.enabled', false, {scopeSelector: '.source.coffee'});
expect(wrapGuide).not.toBeVisible();
});
});
it("leaves alone preferredLineLength if modifyPreferredLineLength is false", () => {
const initial = atom.config.get("editor.preferredLineLength", { scope: editor.getRootScopeDescriptor() });
atom.config.set("wrap-guide.modifyPreferredLineLength", false);
describe('scoped config', function() {
it('::getDefaultColumn returns the scope-specific column value', function() {
atom.config.set('editor.preferredLineLength', 132, {scopeSelector: '.source.js'});
atom.config.set("wrap-guide.columns", [ initial, initial + 10]);
waitsForPromise(() => editorElement.getComponent().getNextUpdatePromise());
waitsForPromise(() => wrapGuide.getDefaultColumn().then((column) => expect(column).toBe(132)));
});
runs(() => {
const length = atom.config.get("editor.preferredLineLength", { scope: editor.getRootScopeDescriptor() });
expect(length).toBe(initial);
it('updates the guide when the scope-specific column changes', function() {
const initial = getLeftPosition(wrapGuide.firstChild);
const column = atom.config.get('editor.preferredLineLength', {scope: editor.getRootScopeDescriptor()});
atom.config.set('editor.preferredLineLength', column + 10, {scope: '.source.js'});
expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial);
});
it('updates the guide when wrap-guide.enabled is set to false', function() {
expect(wrapGuide).toBeVisible();
atom.config.set('wrap-guide.enabled', false, {scopeSelector: '.source.js'});
expect(wrapGuide).not.toBeVisible();
});
});
});
describe("when the editor's scroll left changes", () => it("updates the wrap guide position to a relative position on screen", function() {
editor.setText("a long line which causes the editor to scroll");
editorElement.style.width = "100px";
describe("When only shown if wrapping at preferred line length", () => {
beforeEach(() => {
atom.config.set('wrap-guide.showWrapGuide', 'atPreferredLineLength');
waitsFor(() => editorElement.component.getMaxScrollLeft() > 10);
waitsForPromise(() => atom.packages.activatePackage('wrap-guide'));
runs(function() {
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
editorElement.setScrollLeft(10);
expect(getLeftPosition(wrapGuide.firstChild)).toBe(initial - 10);
expect(wrapGuide.firstChild).toBeVisible();
});
}));
waitsForPromise(() => atom.packages.activatePackage('language-javascript'));
describe("when the editor's grammar changes", function() {
it("updates the wrap guide position", function() {
atom.config.set('editor.preferredLineLength', 20, {scopeSelector: '.source.js'});
const initial = getLeftPosition(wrapGuide.firstChild);
expect(initial).toBeGreaterThan(0);
expect(wrapGuide).toBeVisible();
waitsForPromise(() => atom.packages.activatePackage('language-coffee-script'));
editor.setGrammar(atom.grammars.grammarForScopeName('text.plain.null-grammar'));
expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial);
expect(wrapGuide).toBeVisible();
waitsForPromise(() => atom.workspace.open('sample.txt'));
waitsForPromise(() => atom.workspace.open('sample.js'));
});
it('listens for preferredLineLength updates for the new grammar', function() {
editor.setGrammar(atom.grammars.grammarForScopeName('source.coffee'));
const initial = getLeftPosition(wrapGuide.firstChild);
atom.config.set('editor.preferredLineLength', 20, {scopeSelector: '.source.coffee'});
expect(getLeftPosition(wrapGuide.firstChild)).toBeLessThan(initial);
describe("while the wrapping at preferred line length is active", () => {
beforeEach(() => {
atom.config.set('editor.softWrap', true);
atom.config.set('editor.softWrapAtPreferredLineLength', true);
workspaceElement = atom.views.getView(atom.workspace);
workspaceElement.style.height = "200px";
workspaceElement.style.width = "1500px";
jasmine.attachToDOM(workspaceElement);
runs(() => {
editor = atom.workspace.getActiveTextEditor();
editorElement = editor.getElement();
wrapGuide = editorElement.querySelector(".wrap-guide-container");
});
});
it("should generate wrap-guides as usual until either wrappings are deactivated", () => {
expect(atom.workspace.getTextEditors().length).toBe(2);
function getWrapGuides() {
const wrapGuides = [];
atom.workspace.getTextEditors().forEach((editor) => {
const guides = editor.getElement().querySelectorAll(".wrap-guide");
if (guides && guides.length > 0) { return wrapGuides.push(guides); }
});
return wrapGuides;
}
const scopeDescriptor = editor.getRootScopeDescriptor();
expect([atom.config.get('editor.softWrap'),
atom.config.get('editor.softWrapAtPreferredLineLength')]).toEqual([true, true]);
expect(getWrapGuides().length).toBe(2);
atom.config.set('editor.softWrap', false, {scopeSelector: scopeDescriptor});
expect([atom.config.get('editor.softWrap'),
atom.config.get('editor.softWrap', {scope: scopeDescriptor})]).toEqual([true, false]);
expect(getWrapGuides().length).toBe(1);
atom.config.set('editor.softWrap', true, {scopeSelector: scopeDescriptor});
expect(atom.config.get('editor.softWrap', {scope: scopeDescriptor})).toBe(true);
expect(getWrapGuides().length).toBe(2);
atom.config.set('editor.softWrapAtPreferredLineLength', false, {scopeSelector: scopeDescriptor});
expect([atom.config.get('editor.softWrapAtPreferredLineLength'),
atom.config.get('editor.softWrapAtPreferredLineLength', {scope: scopeDescriptor})]).
toEqual([true, false]);
expect(getWrapGuides().length).toBe(1);
atom.config.unset('editor.softWrapAtPreferredLineLength', {scopeSelector: scopeDescriptor});
expect(atom.config.get('editor.softWrapAtPreferredLineLength', {scope: scopeDescriptor})).toBe(true);
expect(getWrapGuides().length).toBe(2);
atom.config.set('editor.softWrapAtPreferredLineLength', false);
expect([atom.config.get('editor.softWrapAtPreferredLineLength'),
atom.config.get('editor.softWrapAtPreferredLineLength', {scope: scopeDescriptor})]).
toEqual([false, false]);
expect(getWrapGuides().length).toBe(0);
});
it("should adapt when changing the grammar", () => {
expect(atom.workspace.getTextEditors().length).toBe(2);
function getWrapGuides() {
const wrapGuides = [];
atom.workspace.getTextEditors().forEach((editor) => {
const guides = editor.getElement().querySelectorAll(".wrap-guide");
if (guides && guides.length > 0) { return wrapGuides.push(guides); }
});
return wrapGuides;
}
const scopeDescriptor = editor.getRootScopeDescriptor();
expect([atom.config.get('editor.softWrap'),
atom.config.get('editor.softWrapAtPreferredLineLength')]).toEqual([true, true]);
expect(getWrapGuides().length).toBe(2);
atom.config.set('editor.softWrapAtPreferredLineLength', false, {scopeSelector: scopeDescriptor});
expect([atom.config.get('editor.softWrapAtPreferredLineLength'),
atom.config.get('editor.softWrapAtPreferredLineLength', {scope: scopeDescriptor})]).toEqual([true, false]);
expect(getWrapGuides().length).toBe(1);
editor.setGrammar(atom.grammars.grammarForScopeName('source.coffee'));
const new_scopeDescriptor = editor.getRootScopeDescriptor();
expect([scopeDescriptor != new_scopeDescriptor,
atom.config.get('editor.softWrapAtPreferredLineLength', {scope: new_scopeDescriptor})]).
toEqual([true, true]);
expect(getWrapGuides().length).toBe(2);
atom.config.set('editor.softWrapAtPreferredLineLength', false, {scopeSelector: new_scopeDescriptor});
expect(getWrapGuides().length).toBe(1);
});
});
it('listens for wrap-guide.enabled updates for the new grammar', function() {
editor.setGrammar(atom.grammars.grammarForScopeName('source.coffee'));
expect(wrapGuide).toBeVisible();
atom.config.set('wrap-guide.enabled', false, {scopeSelector: '.source.coffee'});
expect(wrapGuide).not.toBeVisible();
describe("while the wrapping is inactive", () => {
beforeEach(() => {
atom.config.set('editor.softWrap', false);
atom.config.set('editor.softWrapAtPreferredLineLength', false);
workspaceElement = atom.views.getView(atom.workspace);
workspaceElement.style.height = "200px";
workspaceElement.style.width = "1500px";
jasmine.attachToDOM(workspaceElement);
runs(() => {
editor = atom.workspace.getActiveTextEditor();
editorElement = editor.getElement();
wrapGuide = editorElement.querySelector(".wrap-guide-container");
});
});
it("should not generate wrap-guides until wrapping at preferred line length is reactivated", () => {
expect(atom.workspace.getTextEditors().length).toBe(2);
function getWrapGuides() {
const wrapGuides = [];
atom.workspace.getTextEditors().forEach((editor) => {
const guides = editor.getElement().querySelectorAll(".wrap-guide");
if (guides && guides.length > 0) { return wrapGuides.push(guides); }
});
return wrapGuides;
}
const scopeDescriptor = editor.getRootScopeDescriptor();
expect([atom.config.get('editor.softWrap'),
atom.config.get('editor.softWrapAtPreferredLineLength')]).toEqual([false, false]);
expect(getWrapGuides().length).toBe(0);
atom.config.set('editor.softWrap', true, {scopeSelector: scopeDescriptor});
expect([atom.config.get('editor.softWrap'),
atom.config.get('editor.softWrap', {scope: scopeDescriptor})]).toEqual([false, true]);
expect(getWrapGuides().length).toBe(0);
atom.config.set('editor.softWrapAtPreferredLineLength', true, {scopeSelector: scopeDescriptor});
expect([atom.config.get('editor.softWrapAtPreferredLineLength'),
atom.config.get('editor.softWrapAtPreferredLineLength', {scope: scopeDescriptor})]).
toEqual([false, true]);
expect(getWrapGuides().length).toBe(1);
});
it("should adapt when changing to another mod", () => {
expect(atom.workspace.getTextEditors().length).toBe(2);
function getWrapGuides() {
const wrapGuides = [];
atom.workspace.getTextEditors().forEach((editor) => {
const guides = editor.getElement().querySelectorAll(".wrap-guide");
if (guides && guides.length > 0) { return wrapGuides.push(guides); }
});
return wrapGuides;
}
const scopeDescriptor = editor.getRootScopeDescriptor();
expect([atom.config.get('editor.softWrap'),
atom.config.get('editor.softWrapAtPreferredLineLength')]).toEqual([false, false]);
expect(getWrapGuides().length).toBe(0);
atom.config.set('editor.softWrap', true, {scopeSelector: scopeDescriptor});
expect(getWrapGuides().length).toBe(0);
atom.config.set('wrap-guide.showWrapGuide', 'wrapping');
expect(getWrapGuides().length).toBe(1);
});
});
});
describe('scoped config', function() {
it('::getDefaultColumn returns the scope-specific column value', function() {
atom.config.set('editor.preferredLineLength', 132, {scopeSelector: '.source.js'});
describe("When only shown if wrapping", () => {
beforeEach(() => {
atom.config.set('wrap-guide.showWrapGuide', 'wrapping');
expect(wrapGuide.getDefaultColumn()).toBe(132);
waitsForPromise(() => atom.packages.activatePackage('wrap-guide'));
waitsForPromise(() => atom.packages.activatePackage('language-javascript'));
waitsForPromise(() => atom.packages.activatePackage('language-coffee-script'));
waitsForPromise(() => atom.workspace.open('sample.txt'));
waitsForPromise(() => atom.workspace.open('sample.js'));
});
it('updates the guide when the scope-specific column changes', function() {
const initial = getLeftPosition(wrapGuide.firstChild);
const column = atom.config.get('editor.preferredLineLength', {scope: editor.getRootScopeDescriptor()});
atom.config.set('editor.preferredLineLength', column + 10, {scope: '.source.js'});
expect(getLeftPosition(wrapGuide.firstChild)).toBeGreaterThan(initial);
describe("while the wrapping is active", () => {
beforeEach(() => {
atom.config.set('editor.softWrap', true);
workspaceElement = atom.views.getView(atom.workspace);
workspaceElement.style.height = "200px";
workspaceElement.style.width = "1500px";
jasmine.attachToDOM(workspaceElement);
runs(() => {
editor = atom.workspace.getActiveTextEditor();
editorElement = editor.getElement();
wrapGuide = editorElement.querySelector(".wrap-guide-container");
});
});
it("should generate wrap-guides as usual until wrapping is deactivated", () => {
expect(atom.workspace.getTextEditors().length).toBe(2);
function getWrapGuides() {
const wrapGuides = [];
atom.workspace.getTextEditors().forEach((editor) => {
const guides = editor.getElement().querySelectorAll(".wrap-guide");
if (guides && guides.length > 0) { return wrapGuides.push(guides); }
});
return wrapGuides;
}
const scopeDescriptor = editor.getRootScopeDescriptor();
expect(atom.config.get('editor.softWrap')).toBe(true);
expect(getWrapGuides().length).toBe(2);
atom.config.set('editor.softWrap', false, {scopeSelector: scopeDescriptor});
expect([atom.config.get('editor.softWrap'),
atom.config.get('editor.softWrap', {scope: scopeDescriptor})]).toEqual([true, false]);
expect(getWrapGuides().length).toBe(1);
});
});
it('updates the guide when wrap-guide.enabled is set to false', function() {
expect(wrapGuide).toBeVisible();
describe("while the wrapping is inactive", () => {
beforeEach(() => {
atom.config.set('editor.softWrap', false);
workspaceElement = atom.views.getView(atom.workspace);
workspaceElement.style.height = "200px";
workspaceElement.style.width = "1500px";
atom.config.set('wrap-guide.enabled', false, {scopeSelector: '.source.js'});
jasmine.attachToDOM(workspaceElement);
expect(wrapGuide).not.toBeVisible();
runs(() => {
editor = atom.workspace.getActiveTextEditor();
editorElement = editor.getElement();
wrapGuide = editorElement.querySelector(".wrap-guide-container");
});
});
it("should not generate wrap-guides until wrapping is reactivated", () => {
expect(atom.workspace.getTextEditors().length).toBe(2);
function getWrapGuides() {
const wrapGuides = [];
atom.workspace.getTextEditors().forEach((editor) => {
const guides = editor.getElement().querySelectorAll(".wrap-guide");
if (guides && guides.length > 0) { return wrapGuides.push(guides); }
});
return wrapGuides;
}
const scopeDescriptor = editor.getRootScopeDescriptor();
expect(atom.config.get('editor.softWrap')).toBe(false);
expect(getWrapGuides().length).toBe(0);
atom.config.set('editor.softWrap', true, {scopeSelector: scopeDescriptor});
expect([atom.config.get('editor.softWrap'),
atom.config.get('editor.softWrap', {scope: scopeDescriptor})]).toEqual([false, true]);
expect(getWrapGuides().length).toBe(1);
});
});
});
});