Merge pull request #478 from pulsar-edit/wrap-guide-decaf

Add decaf changes to `master`
This commit is contained in:
confused_techie 2023-04-09 13:54:15 -07:00 committed by GitHub
commit fe89387509
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 221 additions and 163 deletions

View File

@ -1,26 +0,0 @@
{CompositeDisposable} = require 'atom'
WrapGuideElement = require './wrap-guide-element'
module.exports =
activate: ->
@subscriptions = new CompositeDisposable()
@wrapGuides = new Map()
@subscriptions.add atom.workspace.observeTextEditors (editor) =>
return if @wrapGuides.has(editor)
editorElement = atom.views.getView(editor)
wrapGuideElement = new WrapGuideElement(editor, editorElement)
@wrapGuides.set(editor, wrapGuideElement)
@subscriptions.add editor.onDidDestroy =>
@wrapGuides.get(editor).destroy()
@wrapGuides.delete(editor)
deactivate: ->
@subscriptions.dispose()
@wrapGuides.forEach (wrapGuide, editor) -> wrapGuide.destroy()
@wrapGuides.clear()
uniqueAscending: (list) ->
(list.filter((item, index) -> list.indexOf(item) is index)).sort((a, b) -> a - b)

View File

@ -0,0 +1,34 @@
const {CompositeDisposable} = require('atom');
const WrapGuideElement = require('./wrap-guide-element');
module.exports = {
activate() {
this.subscriptions = new CompositeDisposable();
this.wrapGuides = new Map();
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);
this.wrapGuides.set(editor, wrapGuideElement);
this.subscriptions.add(editor.onDidDestroy(() => {
this.wrapGuides.get(editor).destroy();
this.wrapGuides.delete(editor);
})
);
})
);
},
deactivate() {
this.subscriptions.dispose();
this.wrapGuides.forEach((wrapGuide, editor) => wrapGuide.destroy());
return this.wrapGuides.clear();
},
uniqueAscending(list) {
return (list.filter((item, index) => list.indexOf(item) === index)).sort((a, b) => a - b);
}
};

View File

@ -1,137 +0,0 @@
{CompositeDisposable} = require 'atom'
module.exports =
class WrapGuideElement
constructor: (@editor, @editorElement) ->
@subscriptions = new CompositeDisposable()
@configSubscriptions = new CompositeDisposable()
@element = document.createElement('div')
@element.setAttribute('is', 'wrap-guide')
@element.classList.add('wrap-guide-container')
@attachToLines()
@handleEvents()
@updateGuide()
@element.updateGuide = @updateGuide.bind(this)
@element.getDefaultColumn = @getDefaultColumn.bind(this)
attachToLines: ->
scrollView = @editorElement.querySelector('.scroll-view')
scrollView?.appendChild(@element)
handleEvents: ->
updateGuideCallback = => @updateGuide()
@handleConfigEvents()
@subscriptions.add atom.config.onDidChange 'editor.fontSize', =>
# Wait for editor to finish updating before updating wrap guide
# TODO: Use async/await once this file is converted to JS
@editorElement.getComponent().getNextUpdatePromise().then -> updateGuideCallback()
@subscriptions.add @editorElement.onDidChangeScrollLeft(updateGuideCallback)
@subscriptions.add @editor.onDidChangePath(updateGuideCallback)
@subscriptions.add @editor.onDidChangeGrammar =>
@configSubscriptions.dispose()
@handleConfigEvents()
updateGuideCallback()
@subscriptions.add @editor.onDidDestroy =>
@subscriptions.dispose()
@configSubscriptions.dispose()
@subscriptions.add @editorElement.onDidAttach =>
@attachToLines()
updateGuideCallback()
handleConfigEvents: ->
{uniqueAscending} = require './main'
updatePreferredLineLengthCallback = (args) =>
# ensure that the right-most wrap guide is the preferredLineLength
columns = atom.config.get('wrap-guide.columns', scope: @editor.getRootScopeDescriptor())
if columns.length > 0
columns[columns.length - 1] = args.newValue
columns = uniqueAscending(i for i in columns when i <= args.newValue)
atom.config.set 'wrap-guide.columns', columns,
scopeSelector: ".#{@editor.getGrammar().scopeName}"
@updateGuide()
@configSubscriptions.add atom.config.onDidChange(
'editor.preferredLineLength',
scope: @editor.getRootScopeDescriptor(),
updatePreferredLineLengthCallback
)
updateGuideCallback = => @updateGuide()
@configSubscriptions.add atom.config.onDidChange(
'wrap-guide.enabled',
scope: @editor.getRootScopeDescriptor(),
updateGuideCallback
)
updateGuidesCallback = (args) =>
# ensure that multiple guides stay sorted in ascending order
columns = uniqueAscending(args.newValue)
if columns?.length
atom.config.set('wrap-guide.columns', columns)
atom.config.set 'editor.preferredLineLength', columns[columns.length - 1],
scopeSelector: ".#{@editor.getGrammar().scopeName}"
@updateGuide()
@configSubscriptions.add atom.config.onDidChange(
'wrap-guide.columns',
scope: @editor.getRootScopeDescriptor(),
updateGuidesCallback
)
getDefaultColumn: ->
atom.config.get('editor.preferredLineLength', scope: @editor.getRootScopeDescriptor())
getGuidesColumns: (path, scopeName) ->
columns = atom.config.get('wrap-guide.columns', scope: @editor.getRootScopeDescriptor()) ? []
return columns if columns.length > 0
return [@getDefaultColumn()]
isEnabled: ->
atom.config.get('wrap-guide.enabled', scope: @editor.getRootScopeDescriptor()) ? true
hide: ->
@element.style.display = 'none'
show: ->
@element.style.display = 'block'
updateGuide: ->
if @isEnabled()
@updateGuides()
else
@hide()
updateGuides: ->
@removeGuides()
@appendGuides()
if @element.children.length
@show()
else
@hide()
destroy: ->
@element.remove()
@subscriptions.dispose()
@configSubscriptions.dispose()
removeGuides: ->
while @element.firstChild
@element.removeChild(@element.firstChild)
appendGuides: ->
columns = @getGuidesColumns(@editor.getPath(), @editor.getGrammar().scopeName)
for column in columns
@appendGuide(column) unless column < 0
appendGuide: (column) ->
columnWidth = @editorElement.getDefaultCharacterWidth() * column
columnWidth -= @editorElement.getScrollLeft()
guide = document.createElement('div')
guide.classList.add('wrap-guide')
guide.style.left = "#{Math.round(columnWidth)}px"
@element.appendChild(guide)

View File

@ -0,0 +1,187 @@
const {CompositeDisposable} = require('atom');
module.exports = class WrapGuideElement {
constructor(editor, editorElement) {
this.editor = editor;
this.editorElement = editorElement;
this.subscriptions = new CompositeDisposable();
this.configSubscriptions = new CompositeDisposable();
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.element.updateGuide = this.updateGuide.bind(this);
this.element.getDefaultColumn = this.getDefaultColumn.bind(this);
}
attachToLines() {
const scrollView = this.editorElement.querySelector('.scroll-view');
return (scrollView != null ? scrollView.appendChild(this.element) : undefined);
}
handleEvents() {
const updateGuideCallback = () => this.updateGuide();
this.handleConfigEvents();
this.subscriptions.add(atom.config.onDidChange('editor.fontSize', () => {
// 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());
})
);
this.subscriptions.add(this.editorElement.onDidChangeScrollLeft(updateGuideCallback));
this.subscriptions.add(this.editor.onDidChangePath(updateGuideCallback));
this.subscriptions.add(this.editor.onDidChangeGrammar(() => {
this.configSubscriptions.dispose();
this.handleConfigEvents();
updateGuideCallback();
})
);
this.subscriptions.add(this.editor.onDidDestroy(() => {
this.subscriptions.dispose();
this.configSubscriptions.dispose();
})
);
this.subscriptions.add(this.editorElement.onDidAttach(() => {
this.attachToLines();
updateGuideCallback();
})
);
}
handleConfigEvents() {
const {uniqueAscending} = require('./main');
const updatePreferredLineLengthCallback = 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}`});
}
return this.updateGuide();
};
this.configSubscriptions.add(atom.config.onDidChange(
'editor.preferredLineLength',
{scope: this.editor.getRootScopeDescriptor()},
updatePreferredLineLengthCallback
)
);
const updateGuideCallback = () => this.updateGuide();
this.configSubscriptions.add(atom.config.onDidChange(
'wrap-guide.enabled',
{scope: this.editor.getRootScopeDescriptor()},
updateGuideCallback
)
);
const updateGuidesCallback = 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);
atom.config.set('editor.preferredLineLength', columns[columns.length - 1],
{scopeSelector: `.${this.editor.getGrammar().scopeName}`});
return this.updateGuide();
}
};
return this.configSubscriptions.add(atom.config.onDidChange(
'wrap-guide.columns',
{scope: this.editor.getRootScopeDescriptor()},
updateGuidesCallback
)
);
}
getDefaultColumn() {
return atom.config.get('editor.preferredLineLength', {scope: this.editor.getRootScopeDescriptor()});
}
getGuidesColumns(path, scopeName) {
let left;
const columns = (left = atom.config.get('wrap-guide.columns', {scope: this.editor.getRootScopeDescriptor()})) != null ? left : [];
if (columns.length > 0) { return columns; }
return [this.getDefaultColumn()];
}
isEnabled() {
let left;
return (left = atom.config.get('wrap-guide.enabled', {scope: this.editor.getRootScopeDescriptor()})) != null ? left : true;
}
hide() {
return this.element.style.display = 'none';
}
show() {
return this.element.style.display = 'block';
}
updateGuide() {
if (this.isEnabled()) {
return this.updateGuides();
} else {
return this.hide();
}
}
updateGuides() {
this.removeGuides();
this.appendGuides();
if (this.element.children.length) {
return this.show();
} else {
return this.hide();
}
}
destroy() {
this.element.remove();
this.subscriptions.dispose();
return this.configSubscriptions.dispose();
}
removeGuides() {
return (() => {
const result = [];
while (this.element.firstChild) {
result.push(this.element.removeChild(this.element.firstChild));
}
return result;
})();
}
appendGuides() {
const columns = this.getGuidesColumns(this.editor.getPath(), this.editor.getGrammar().scopeName);
return (() => {
const result = [];
for (let column of columns) {
if (!(column < 0)) {
result.push(this.appendGuide(column));
} else {
result.push(undefined);
}
}
return result;
})();
}
appendGuide(column) {
let columnWidth = this.editorElement.getDefaultCharacterWidth() * column;
columnWidth -= this.editorElement.getScrollLeft();
const guide = document.createElement('div');
guide.classList.add('wrap-guide');
guide.style.left = `${Math.round(columnWidth)}px`;
return this.element.appendChild(guide);
}
};