Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
moveRight(position, { copy = false } = {}) {
if (this.lineInfo.length === 0)
return new Point();
position = Point.fromObject(position, copy);
let tokenLocator = this.tokenLocatorForPosition(position);
if (!tokenLocator)
return null;
let [ row, tokenIndex, line, token ] = tokenLocator;
// if we're inside the token, or on its left edge
if (position.column < token.outputOffset + token.outputLength) {
// if we're a static token, we can just move inside the token
if (token.type === STATIC_TOKEN) {
position.column += 1;
const _ = require('underscore-plus')
const Grim = require('grim')
const FirstMate = require('first-mate')
const {Disposable, CompositeDisposable} = require('event-kit')
const TextMateLanguageMode = require('./text-mate-language-mode')
const Token = require('./token')
const fs = require('fs-plus')
const {Point, Range} = require('text-buffer')
const GRAMMAR_SELECTION_RANGE = Range(Point.ZERO, Point(10, 0)).freeze()
const PATH_SPLIT_REGEX = new RegExp('[/.]')
// Extended: This class holds the grammars used for tokenizing.
//
// An instance of this class is always available as the `atom.grammars` global.
module.exports =
class GrammarRegistry {
constructor ({config} = {}) {
this.config = config
this.subscriptions = new CompositeDisposable()
this.textmateRegistry = new FirstMate.GrammarRegistry({maxTokensPerLine: 100, maxLineLength: 1000})
this.clear()
}
clear () {
this.textmateRegistry.clear()
const {target, button, ctrlKey, shiftKey, metaKey} = event
// Only handle mousedown events for left mouse button
if (button !== 0) return
const clickedScreenRow = this.screenPositionForMouseEvent(event).row
const startBufferRow = model.bufferPositionForScreenPosition([clickedScreenRow, 0]).row
if (target && target.matches('.foldable .icon-right')) {
model.toggleFoldAtBufferRow(startBufferRow)
return
}
const addOrRemoveSelection = metaKey || (ctrlKey && this.getPlatform() !== 'darwin')
const endBufferRow = model.bufferPositionForScreenPosition([clickedScreenRow, Infinity]).row
const clickedLineBufferRange = Range(Point(startBufferRow, 0), Point(endBufferRow + 1, 0))
let initialBufferRange
if (shiftKey) {
const lastSelection = model.getLastSelection()
initialBufferRange = lastSelection.getBufferRange()
lastSelection.setBufferRange(initialBufferRange.union(clickedLineBufferRange), {
reversed: clickedScreenRow < lastSelection.getScreenRange().start.row,
autoscroll: false,
preserveFolds: true,
suppressSelectionMerge: true
})
} else {
initialBufferRange = clickedLineBufferRange
if (addOrRemoveSelection) {
model.addSelectionForBufferRange(clickedLineBufferRange, {autoscroll: false, preserveFolds: true})
} else {
scopeDescriptorForPosition(position) {
let scopes;
const { row, column } = this.buffer.clipPosition(
Point.fromObject(position)
);
const iterator = this.tokenizedLineForRow(row).getTokenIterator();
while (iterator.next()) {
if (iterator.getBufferEnd() > column) {
scopes = iterator.getScopes();
break;
}
}
// rebuild scope of last token if we iterated off the end
if (!scopes) {
scopes = iterator.getScopes();
scopes.push(...iterator.getScopeEnds().reverse());
}
moveDown(position, { copy = false, amount = 1 } = {}) {
if (this.lineInfo.length === 0)
return new Point();
position = Point.fromObject(position, copy);
// if jumping would bring us below the very last line, we just go to the end of this line
if (position.row + amount >= this.lineInfo.length) {
position.row = this.lineInfo.length - 1;
position.column = this.lineInfo[position.row].outputLineLength;
} else {
position.row += amount;
// if we land on the left edge, short-circuit the rest of the procedure
if (position.column === 0) {
return position;
// if we land on the right edge or beyond, we can short-circuit the rest of the procedure too
} else if (position.column >= this.lineInfo[position.row].outputLineLength) {
position.column = this.lineInfo[position.row].outputLineLength;
moveLeft(position, { copy = false } = {}) {
if (this.lineInfo.length === 0)
return new Point();
position = Point.fromObject(position, copy);
let tokenLocator = this.tokenLocatorForPosition(position);
if (!tokenLocator)
return null;
let [ row, tokenIndex, line, token ] = tokenLocator;
// if we're inside the token, or on its right edge
if (position.column > token.outputOffset) {
// if we're a static token, we can just move inside the token
if (token.type === STATIC_TOKEN) {
position.column -= 1;
// otherwise, we need to teleport to the beginning of the token
moveUp(position, { copy = false, amount = 1 } = {}) {
if (this.lineInfo.length === 0)
return new Point();
position = Point.fromObject(position, copy);
// if jumping would bring us above the very first line, we just go to the beginning of this line
if (position.row - amount < 0) {
position.row = 0;
position.column = 0;
} else {
position.row -= amount;
// if we land on the left edge, short-circuit the rest of the procedure
if (position.column === 0) {
return position;
// if we land on the right edge or beyond, we can short-circuit the rest of the procedure too
} else if (position.column >= this.lineInfo[position.row].outputLineLength) {
position.column = this.lineInfo[position.row].outputLineLength;
moveTo(position, { copy = false } = {}) {
if (this.lineInfo.length === 0)
return new Point();
position = Point.fromObject(position, copy);
position.row = Math.max(0, Math.min(position.row, this.lineInfo.length - 1));
position.column = Math.max(0, Math.min(position.column, this.lineInfo[position.row].outputLineLength));
if (position.column === 0 || position.column === this.lineInfo[position.row].outputLineLength)
return position;
let tokenLocator = this.tokenLocatorForPosition(position);
let [ row, tokenIndex, line, token ] = tokenLocator;
if (token.type === DYNAMIC_TOKEN) {
// if we're closer to the right side, we jump to it
if (position.column >= token.outputOffset + token.outputLength / 2) {
position.column = token.outputOffset + token.outputLength;
const handleBufferState = bufferState => {
if (bufferState.shouldDestroyOnFileDelete == null) {
bufferState.shouldDestroyOnFileDelete = () =>
atom.config.get('core.closeDeletedFileTabs');
}
// Use a little guilty knowledge of the way TextBuffers are serialized.
// This allows TextBuffers that have never been saved (but have filePaths) to be deserialized, but prevents
// TextBuffers backed by files that have been deleted from being saved.
bufferState.mustExist = bufferState.digestWhenLastPersisted !== false;
return TextBuffer.deserialize(bufferState).catch(_ => {
this.retiredBufferIDs.add(bufferState.id);
this.retiredBufferPaths.add(bufferState.filePath);
return null;
});
};
row === lastRow ||
_.isEqual(this.stackForRow(row), previousStack)
) {
filledRegion = true;
endRow = row;
break;
}
row++;
}
this.validateRow(endRow);
if (!filledRegion) this.invalidateRow(endRow + 1);
this.emitter.emit(
'did-change-highlighting',
Range(Point(startRow, 0), Point(endRow + 1, 0))
);
}
if (this.firstInvalidRow() != null) {
this.tokenizeInBackground();
} else {
this.markTokenizationComplete();
}
}