Skip to content

Commit

Permalink
Copy misc/blocks to lib_src
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Apr 13, 2020
1 parent 7fc7bfc commit 8ec60c8
Showing 1 changed file with 167 additions and 0 deletions.
167 changes: 167 additions & 0 deletions lib_src/misc/blocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
'use babel'
// TODO: docstrings

import { forLines } from './scopes'

export function getLine (ed, l) {
return {
scope: ed.scopeDescriptorForBufferPosition([l, 0]).scopes,
line: ed.getTextInBufferRange([[l, 0], [l, Infinity]])
}
}

function isBlank ({line, scope}, allowDocstrings = false) {
for (const s of scope) {
if (/\bcomment\b/.test(s) || (!allowDocstrings && /\bdocstring\b/.test(s))) {
return true
}
}
return /^\s*(#.*)?$/.test(line)
}
function isEnd ({ line, scope }) {
if (isStringEnd({ line, scope })) {
return true
}
return /^(end\b|\)|\]|\})/.test(line)
}
function isStringEnd ({ line, scope }) {
scope = scope.join(' ')
return /\bstring\.multiline\.end\b/.test(scope) ||
(/\bstring\.end\b/.test(scope) && /\bbacktick\b/.test(scope))
}
function isCont ({ line, scope }) {
scope = scope.join(' ')
if (/\bstring\b/.test(scope) && !(/\bpunctuation\.definition\.string\b/.test(scope))) {
return true
}

return line.match(/^(else|elseif|catch|finally)\b/)
}
function isStart (lineInfo) {
return !(/^\s/.test(lineInfo.line) || isBlank(lineInfo) || isEnd(lineInfo) || isCont(lineInfo))
}

function walkBack(ed, row) {
while ((row > 0) && !isStart(getLine(ed, row))) {
row--
}
return row
}

function walkForward (ed, start) {
let end = start
let mark = start
while (mark < ed.getLastBufferRow()) {
mark++
const lineInfo = getLine(ed, mark)

if (isStart(lineInfo)) {
break
}
if (isEnd(lineInfo)) {
// An `end` only counts when there still are unclosed blocks (indicated by `forLines`
// returning a non-empty array).
// If the line closes a multiline string we also take that as ending the block.
if (
!(forLines(ed, start, mark-1).length === 0) ||
isStringEnd(lineInfo)
) {
end = mark
}
} else if (!(isBlank(lineInfo) || isStart(lineInfo))) {
end = mark
}
}
return end
}

function getRange (ed, row) {
const start = walkBack(ed, row)
const end = walkForward(ed, start)
if (start <= row && row <= end) {
return [[start, 0], [end, Infinity]]
}
}

function getSelection (ed, sel) {
const {start, end} = sel.getBufferRange()
const range = [[start.row, start.column], [end.row, end.column]]
while (isBlank(getLine(ed, range[0][0]), true) && (range[0][0] <= range[1][0])) {
range[0][0]++
range[0][1] = 0
}
while (isBlank(getLine(ed, range[1][0]), true) && (range[1][0] >= range[0][0])) {
range[1][0]--
range[1][1] = Infinity
}
return range
}

export function moveNext (ed, sel, range) {
// Ensure enough room at the end of the buffer
const row = range[1][0]
let last
while ((last = ed.getLastBufferRow()) < (row+2)) {
if ((last !== row) && !isBlank(getLine(ed, last))) {
break
}
sel.setBufferRange([[last, Infinity], [last, Infinity]])
sel.insertText('\n')
}
// Move the cursor
let to = row + 1
while ((to < ed.getLastBufferRow()) && isBlank(getLine(ed, to))) {
to++
}
to = walkForward(ed, to)
return sel.setBufferRange([[to, Infinity], [to, Infinity]])
}

function getRanges (ed) {
const ranges = ed.getSelections().map(sel => {
return {
selection: sel,
range: sel.isEmpty() ?
getRange(ed, sel.getHeadBufferPosition().row) :
getSelection(ed, sel)
}
})
return ranges.filter(({ range }) => {
return range && ed.getTextInBufferRange(range).trim()
})
}

export function get (ed) {
return getRanges(ed).map(({ range, selection }) => {
return {
range,
selection,
line: range[0][0],
text: ed.getTextInBufferRange(range)
}
})
}

export function getLocalContext (editor, row) {
const range = getRange(editor, row)
const context = range ? editor.getTextInBufferRange(range) : ''
// NOTE:
// backend code expects startRow to be number for most cases, e.g.: `row = row - startRow`
// so let's just return `0` when there is no local context
// to check there is a context or not, just check `isempty(context)`
const startRow = range ? range[0][0] : 0
return {
context,
startRow
}
}

export function select (ed = atom.workspace.getActiveTextEditor()) {
if (!ed) return
return ed.mutateSelectedText(selection => {
const range = getRange(ed, selection.getHeadBufferPosition().row)
if (range) {
selection.setBufferRange(range)
}
})
}

0 comments on commit 8ec60c8

Please sign in to comment.