Skip to content

Commit

Permalink
Allow color functions to use arbitrary scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
georgewfraser committed May 25, 2019
1 parent 1331402 commit 8f5d623
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
out
node_modules
.vscode-test/
*.vsix
*.vsix
83 changes: 42 additions & 41 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as Parser from 'web-tree-sitter'
import * as path from 'path'
import * as colors from './colors'

type ColorFunction = (x: Parser.SyntaxNode, editor: vscode.TextEditor) => {types: Parser.SyntaxNode[], fields: Parser.SyntaxNode[], functions: Parser.SyntaxNode[]}
type ColorFunction = (x: Parser.SyntaxNode, editor: vscode.TextEditor) => [Parser.SyntaxNode, string][]

function colorGo(root: Parser.SyntaxNode, editor: vscode.TextEditor) {
// Guess package names based on paths
Expand Down Expand Up @@ -43,9 +43,7 @@ function colorGo(root: Parser.SyntaxNode, editor: vscode.TextEditor) {
return this.parent == null
}
}
var types: Parser.SyntaxNode[] = []
var fields: Parser.SyntaxNode[] = []
var functions: Parser.SyntaxNode[] = []
const colors: [Parser.SyntaxNode, string][] = []
function scanRoot(root: Parser.SyntaxNode) {
const scope = new Scope(null)
for (const decl of root.children) {
Expand All @@ -66,16 +64,16 @@ function colorGo(root: Parser.SyntaxNode, editor: vscode.TextEditor) {
// Add colors
if (x.type == 'identifier' && x.parent != null && x.parent.type == 'function_declaration') {
// func f() { ... }
functions.push(x)
colors.push([x, 'entity.name.function'])
} else if (x.type == 'type_identifier') {
// x: type
types.push(x)
colors.push([x, 'entity.name.type'])
} else if (x.type == 'selector_expression' && x.firstChild!.type == 'identifier' && scope.isPackage(x.firstChild!.text)) {
// pkg.member
return
} else if (x.type == 'field_identifier') {
// obj.member
fields.push(x)
colors.push([x, 'variable'])
}
// Add locals to scope
if (!scope.isRoot() && ['parameter_declaration', 'var_spec', 'const_spec'].includes(x.type)) {
Expand Down Expand Up @@ -105,35 +103,31 @@ function colorGo(root: Parser.SyntaxNode, editor: vscode.TextEditor) {
}
scanRoot(root)

return {types, fields, functions}
return colors
}

function colorTypescript(x: Parser.SyntaxNode, editor: vscode.TextEditor) {
var types: Parser.SyntaxNode[] = []
var fields: Parser.SyntaxNode[] = []
var functions: Parser.SyntaxNode[] = []
const colors: [Parser.SyntaxNode, string][] = []
function scan(x: Parser.SyntaxNode) {
if (!isVisible(x, editor)) return
if (x.type == 'identifier' && x.parent != null && x.parent.type == 'function') {
functions.push(x)
colors.push([x, 'entity.name.function'])
} else if (x.type == 'type_identifier' || x.type == 'predefined_type') {
types.push(x)
colors.push([x, 'entity.name.type'])
} else if (x.type == 'property_identifier') {
fields.push(x)
colors.push([x, 'variable'])
}
for (const child of x.children) {
scan(child)
}
}
scan(x)

return {types, fields, functions}
return colors
}

function colorRust(x: Parser.SyntaxNode, editor: vscode.TextEditor) {
var types: Parser.SyntaxNode[] = []
var fields: Parser.SyntaxNode[] = []
var functions: Parser.SyntaxNode[] = []
const colors: [Parser.SyntaxNode, string][] = []
function looksLikeType(id: string) {
if (id.length == 0) return false
if (id[0] != id[0].toUpperCase()) return false
Expand All @@ -144,7 +138,7 @@ function colorRust(x: Parser.SyntaxNode, editor: vscode.TextEditor) {
}
function scanUse(x: Parser.SyntaxNode) {
if (x.type == 'identifier' && looksLikeType(x.text)) {
types.push(x)
colors.push([x, 'entity.name.type'])
}
for (const child of x.children) {
scanUse(child)
Expand All @@ -153,50 +147,48 @@ function colorRust(x: Parser.SyntaxNode, editor: vscode.TextEditor) {
function scan(x: Parser.SyntaxNode) {
if (!isVisible(x, editor)) return
if (x.type == 'identifier' && x.parent != null && x.parent.type == 'function_item' && x.parent.parent != null && x.parent.parent.type == 'declaration_list') {
fields.push(x)
colors.push([x, 'variable'])
} else if (x.type == 'identifier' && x.parent != null && x.parent.type == 'function_item') {
functions.push(x)
colors.push([x, 'entity.name.function'])
} else if (x.type == 'identifier' && x.parent != null && x.parent.type == 'scoped_identifier' && x.parent.parent != null && x.parent.parent.type == 'function_declarator') {
functions.push(x)
colors.push([x, 'entity.name.function'])
} else if (x.type == 'use_declaration') {
scanUse(x)
return
} else if (x.type == 'type_identifier' || x.type == 'primitive_type') {
types.push(x)
colors.push([x, 'entity.name.type'])
} else if (x.type == 'field_identifier') {
fields.push(x)
colors.push([x, 'variable'])
}
for (const child of x.children) {
scan(child)
}
}
scan(x)

return {types, fields, functions}
return colors
}

function colorCpp(x: Parser.SyntaxNode, editor: vscode.TextEditor) {
var types: Parser.SyntaxNode[] = []
var fields: Parser.SyntaxNode[] = []
var functions: Parser.SyntaxNode[] = []
const colors: [Parser.SyntaxNode, string][] = []
function scan(x: Parser.SyntaxNode) {
if (!isVisible(x, editor)) return
if (x.type == 'identifier' && x.parent != null && x.parent.type == 'function_declarator') {
functions.push(x)
colors.push([x, 'entity.name.function'])
} else if (x.type == 'identifier' && x.parent != null && x.parent.type == 'scoped_identifier' && x.parent.parent != null && x.parent.parent.type == 'function_declarator') {
functions.push(x)
colors.push([x, 'entity.name.function'])
} else if (x.type == 'type_identifier') {
types.push(x)
colors.push([x, 'entity.name.type'])
} else if (x.type == 'field_identifier') {
fields.push(x)
colors.push([x, 'variable'])
}
for (const child of x.children) {
scan(child)
}
}
scan(x)

return {types, fields, functions}
return colors
}

function isVisible(x: Parser.SyntaxNode, editor: vscode.TextEditor) {
Expand Down Expand Up @@ -341,19 +333,28 @@ export async function activate(context: vscode.ExtensionContext) {
}
}
}
const warnedScopes = new Set<string>()
function colorEditor(editor: vscode.TextEditor) {
const t = trees[editor.document.uri.toString()]
if (t == null) return
const language = languages[editor.document.languageId]
if (language == null) return
const {types, fields, functions} = language.color(t.rootNode, editor)
let dec: vscode.TextEditorDecorationType|undefined
dec = decoration('entity.name.type')
if (dec) editor.setDecorations(dec, types.map(range))
dec = decoration('variable')
if (dec) editor.setDecorations(dec, fields.map(range))
dec = decoration('entity.name.function')
if (dec) editor.setDecorations(dec, functions.map(range))
const colors = language.color(t.rootNode, editor)
const nodes = new Map<string, Parser.SyntaxNode[]>()
for (const [x, scope] of colors) {
if (!nodes.has(scope)) nodes.set(scope, [])
nodes.get(scope)!.push(x)
}
for (const scope of nodes.keys()) {
const dec = decoration(scope)
if (dec) {
const ranges = nodes.get(scope)!.map(range)
editor.setDecorations(dec, ranges)
} else if (!warnedScopes.has(scope)) {
console.warn(scope, 'was not found in the current theme')
warnedScopes.add(scope)
}
}
}
function colorAllOpen() {
vscode.window.visibleTextEditors.forEach(open)
Expand Down

0 comments on commit 8f5d623

Please sign in to comment.