Skip to content

Commit

Permalink
feat(semanticTokens)!: token highlight groups
Browse files Browse the repository at this point in the history
CocSemType + type
CocSemMod + modifier
CocSemTypeMod + type + modifier

The highlight group didn't need to be defined first

related #4659
  • Loading branch information
fannheyward committed Jun 8, 2023
1 parent edcc376 commit 0cb6074
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 88 deletions.
23 changes: 9 additions & 14 deletions doc/coc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3320,27 +3320,22 @@ Semantic highlight groups are starts with `CocSem` which link to related
highlight groups, use variable |g:coc_default_semantic_highlight_groups| to
disable creation of these highlight groups.

The highlight groups rules:
>
`CocSemType + type` for types
`CocSemMod + modifier` for modifiers
`CocSemTypeMode + type + modifier` for modifier with type
<

Only semantic tokens types and `deprecated` modifier have default
highlight groups.

You need create highlight groups for highlight other modifiers and/or specific
modifier with type, for example:
>
" Add highlights for defaultLibrary modifier
hi link CocSemDefaultLibrary TSOtherDefaultLibrary
hi link CocSemDefaultLibraryClass TSTypeDefaultLibrary
hi link CocSemDefaultLibraryInterface TSTypeDefaultLibrary
hi link CocSemDefaultLibraryEnum TSTypeDefaultLibrary
hi link CocSemDefaultLibraryType TSTypeDefaultLibrary
hi link CocSemDefaultLibraryNamespace TSTypeDefaultLibrary
" Add highlights for declaration modifier
hi link CocSemDeclaration TSOtherDeclaration
hi link CocSemDeclarationClass TSTypeDeclaration
hi link CocSemDeclarationInterface TSTypeDeclaration
hi link CocSemDeclarationEnum TSTypeDeclaration
hi link CocSemDeclarationType TSTypeDeclaration
hi link CocSemDeclarationNamespace TSTypeDeclaration
hi link CocSemModDeclaration Declaration
hi link CocSemTypeModClassDeclaration ClassDeclaration
<
The modifier highlight groups have higher priority.

Expand Down
7 changes: 7 additions & 0 deletions history.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 2023-06-08

- Break change: semanticTokens highlight groups changed:
- `CocSem + type` to `CocSemType + type`
- `CocSem + modifier` to `CocSemMod + modifier`
- `CocSem + modifier + type` to `CocSemTypeMod + type + modifier`

# 2023-01-30

- Always show `cancellable` progress as notification without check
Expand Down
49 changes: 25 additions & 24 deletions plugin/coc.vim
Original file line number Diff line number Diff line change
Expand Up @@ -557,32 +557,33 @@ function! s:Highlight() abort

if get(g:, 'coc_default_semantic_highlight_groups', 1)
let hlMap = {
\ 'Namespace': ['@namespace', 'Include'],
\ 'Type': ['@type', 'Type'],
\ 'Class': ['@constructor', 'Special'],
\ 'Enum': ['@type', 'Type'],
\ 'Interface': ['@type', 'Type'],
\ 'Struct': ['@structure', 'Identifier'],
\ 'TypeNamespace': ['@namespace', 'Include'],
\ 'TypeType': ['@type', 'Type'],
\ 'TypeClass': ['@constructor', 'Special'],
\ 'TypeEnum': ['@type', 'Type'],
\ 'TypeInterface': ['@type', 'Type'],
\ 'TypeStruct': ['@structure', 'Identifier'],
\ 'TypeTypeParameter': ['@parameter', 'Identifier'],
\ 'TypeParameter': ['@parameter', 'Identifier'],
\ 'Parameter': ['@parameter', 'Identifier'],
\ 'Variable': ['@variable', 'Identifier'],
\ 'Property': ['@property', 'Identifier'],
\ 'EnumMember': ['@property', 'Constant'],
\ 'Event': ['@keyword', 'Keyword'],
\ 'Function': ['@function', 'Function'],
\ 'Method': ['@method', 'Function'],
\ 'Macro': ['@constant.macro', 'Define'],
\ 'Keyword': ['@keyword', 'Keyword'],
\ 'Modifier': ['@storageclass', 'StorageClass'],
\ 'Comment': ['@comment', 'Comment'],
\ 'String': ['@string', 'String'],
\ 'Number': ['@number', 'Number'],
\ 'Boolean': ['@boolean', 'Boolean'],
\ 'Regexp': ['@string.regex', 'String'],
\ 'Operator': ['@operator', 'Operator'],
\ 'Decorator': ['@symbol', 'Identifier'],
\ 'Deprecated': ['@text.strike', 'CocDeprecatedHighlight']
\ 'TypeVariable': ['@variable', 'Identifier'],
\ 'TypeProperty': ['@property', 'Identifier'],
\ 'TypeEnumMember': ['@property', 'Constant'],
\ 'TypeEvent': ['@keyword', 'Keyword'],
\ 'TypeFunction': ['@function', 'Function'],
\ 'TypeMethod': ['@method', 'Function'],
\ 'TypeMacro': ['@constant.macro', 'Define'],
\ 'TypeKeyword': ['@keyword', 'Keyword'],
\ 'TypeModifier': ['@storageclass', 'StorageClass'],
\ 'TypeComment': ['@comment', 'Comment'],
\ 'TypeString': ['@string', 'String'],
\ 'TypeNumber': ['@number', 'Number'],
\ 'TypeBoolean': ['@boolean', 'Boolean'],
\ 'TypeRegexp': ['@string.regex', 'String'],
\ 'TypeOperator': ['@operator', 'Operator'],
\ 'TypeDecorator': ['@symbol', 'Identifier'],
\ 'ModDeprecated': ['@text.strike', 'CocDeprecatedHighlight']
\ }
" TODO: add CocSemModXXX and CocSemTypeModeXXX
for [key, value] in items(hlMap)
let ts = get(value, 0, '')
let fallback = get(value, 1, '')
Expand Down
12 changes: 2 additions & 10 deletions src/__tests__/handler/semanticTokens.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ describe('semanticTokens', () => {
}
}
}, { tokenModifiers: [], tokenTypes: [] }))
await semanticTokens.fetchHighlightGroups()
await semanticTokens.showHighlightInfo()
let buf = await nvim.buffer
let lines = await buf.lines
Expand Down Expand Up @@ -339,7 +338,7 @@ describe('semanticTokens', () => {
let buf = await win.buffer
let lines = await buf.lines
let content = lines.join('\n')
expect(content).toMatch('CocSemDeclarationFunction')
expect(content).toMatch('CocSemTypeFunction')
await window.moveTo({ line: 1, character: 0 })
await commandManager.executeCommand('semanticTokens.inspect')
win = await helper.getFloat()
Expand Down Expand Up @@ -717,7 +716,7 @@ describe('semanticTokens', () => {
await nvim.call('CocAction', 'semanticHighlight')
const highlights = await nvim.call("coc#highlight#get_highlights", [doc.bufnr, 'semanticTokens']) as any[]
expect(highlights.length).toBeGreaterThan(0)
expect(highlights[0][0]).toBe('CocSemKeyword')
expect(highlights[0][0]).toBe('CocSemTypeKeyword')
})
})

Expand Down Expand Up @@ -761,17 +760,10 @@ describe('semanticTokens', () => {
// @ts-ignore
workspace._env.updateHighlight = true
expect(enabled).toBe(false)
semanticTokens.staticConfig.highlightGroups = ['CocSemKeyword']
expect(() => {
item.checkState()
}).toThrow('provider not found')
registerProvider()
doc = await helper.createDocument('t.rs')
item = semanticTokens.getItem(doc.bufnr)
semanticTokens.staticConfig.highlightGroups = []
expect(() => {
item.checkState()
}).toThrow('Unable to find highlight groups')
})
})

Expand Down
57 changes: 27 additions & 30 deletions src/handler/semanticTokens/buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ const highlightGroupMap: Map<string, string> = new Map()

export interface StaticConfig {
filetypes: string[] | null
highlightGroups: ReadonlyArray<string>
}

export default class SemanticTokensBuffer implements SyncItem {
Expand Down Expand Up @@ -190,7 +189,6 @@ export default class SemanticTokensBuffer implements SyncItem {
if (!workspace.env.updateHighlight) throw new Error(`Can't perform highlight update, highlight update requires vim >= 8.1.1719 or neovim >= 0.5.0`)
if (!this.configEnabled) throw new Error(`Semantic tokens highlight not enabled for current filetype: ${this.doc.filetype}`)
if (!this.hasProvider || !this.hasLegend) throw new Error(`SemanticTokens provider not found for ${this.doc.uri}`)
if (this.staticConfig.highlightGroups.length === 0) throw new Error(`Unable to find highlight groups starts with CocSem`)
}

public async getTokenRanges(
Expand Down Expand Up @@ -232,42 +230,41 @@ export default class SemanticTokensBuffer implements SyncItem {
* Single line only.
*/
private addHighlightItems(highlights: SemanticTokenRange[], range: [number, number, number], tokenType: string, tokenModifiers: string[]): void {
// highlight groups:
// CocSem + Type + type
// CocSem + Mod + modifier
// CocSem + TypeMod + type + modifier

let { combinedModifiers } = this.config
let { highlightGroups } = this.staticConfig
let highlightGroup: string
let combine = false
// Compose highlight group CocSem + modifier + type
for (let item of tokenModifiers) {
let hlGroup = HLGROUP_PREFIX + toHighlightPart(item) + toHighlightPart(tokenType)
if (highlightGroups.includes(hlGroup)) {
combine = combinedModifiers.includes(item)
highlightGroup = hlGroup
break
}
}
if (!highlightGroup) {
for (let modifier of tokenModifiers) {
let hlGroup = HLGROUP_PREFIX + toHighlightPart(modifier)
if (highlightGroups.includes(hlGroup)) {
highlightGroup = hlGroup
combine = combinedModifiers.includes(modifier)
break
}
}
}
if (!highlightGroup) {
let hlGroup = HLGROUP_PREFIX + toHighlightPart(tokenType)
if (highlightGroups.includes(hlGroup)) {
highlightGroup = hlGroup
}
}

highlights.push({
range,
tokenType,
combine,
hlGroup: highlightGroup,
hlGroup: HLGROUP_PREFIX + 'Type' + toHighlightPart(tokenType),
tokenModifiers,
})

for (let modifier of tokenModifiers) {
combine = combinedModifiers.includes(modifier)

highlights.push({
range,
tokenType,
combine,
hlGroup: HLGROUP_PREFIX + 'Mode' + toHighlightPart(modifier),
tokenModifiers,
})

highlights.push({
range,
tokenType,
combine,
hlGroup: HLGROUP_PREFIX + 'TypeMod' + toHighlightPart(tokenType) + toHighlightPart(modifier),
tokenModifiers,
})
}
}

private toHighlightItems(highlights: ReadonlyArray<SemanticTokenRange>, startLine?: number, endLine?: number): HighlightItem[] {
Expand Down
12 changes: 2 additions & 10 deletions src/handler/semanticTokens/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import BufferSync from '../../model/bufferSync'
import Highlighter from '../../model/highligher'
import { Documentation, FloatFactory } from '../../types'
import { disposeAll } from '../../util'
import { distinct, isFalsyOrEmpty, toArray } from '../../util/array'
import { distinct, toArray } from '../../util/array'
import type { Disposable } from '../../util/protocol'
import { toErrorText, toText, upperFirst } from '../../util/string'
import { toErrorText, toText } from '../../util/string'
import window from '../../window'
import workspace from '../../workspace'
import SemanticTokensBuffer, { HLGROUP_PREFIX, NAMESPACE, StaticConfig, toHighlightPart } from './buffer'
Expand All @@ -28,7 +28,6 @@ export default class SemanticTokens {
constructor(private nvim: Neovim) {
this.staticConfig = {
filetypes: getFiletypes(),
highlightGroups: []
}
workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('semanticTokens')) {
Expand Down Expand Up @@ -76,7 +75,6 @@ export default class SemanticTokens {
return new SemanticTokensBuffer(this.nvim, doc, this.staticConfig)
})
languages.onDidSemanticTokensRefresh(async selector => {
if (isFalsyOrEmpty(this.staticConfig.highlightGroups)) await this.fetchHighlightGroups()
let visibleBufs = window.visibleTextEditors.map(o => o.document.bufnr)
for (let item of this.highlighters.items) {
if (!workspace.match(selector, item.doc)) continue
Expand Down Expand Up @@ -157,11 +155,6 @@ export default class SemanticTokens {
floatFactory?.close()
}

public async fetchHighlightGroups(): Promise<void> {
let highlightGroups = await this.nvim.call('coc#util#semantic_hlgroups') as string[]
this.staticConfig.highlightGroups = highlightGroups
}

public async getCurrentItem(): Promise<SemanticTokensBuffer | undefined> {
let buf = await this.nvim.buffer
return this.getItem(buf.id)
Expand All @@ -176,7 +169,6 @@ export default class SemanticTokens {
public async highlightCurrent(): Promise<void> {
let item = await this.getCurrentItem()
if (!item || !item.enabled) throw new Error(`Unable to perform semantic highlights for current buffer.`)
await this.fetchHighlightGroups()
await item.forceHighlight()
}

Expand Down

0 comments on commit 0cb6074

Please sign in to comment.