Skip to content

Commit 3d3b75c

Browse files
authored
Added support for harper in markdown files (dense-analysis#5104)
1 parent 0369442 commit 3d3b75c

File tree

10 files changed

+166
-1
lines changed

10 files changed

+166
-1
lines changed

ale_linters/markdown/harper.vim

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
" Author: Armand Halbert <armand.halbert@gmail.com>
2+
" Description: Harper for Markdown files
3+
4+
call ale#Set('markdown_harper_config', {
5+
\ 'harper-ls': {
6+
\ 'diagnosticSeverity': 'hint',
7+
\ 'dialect': 'American',
8+
\ 'linters': {
9+
\ 'SpellCheck': v:true,
10+
\ 'SentenceCapitalization': v:true,
11+
\ 'RepeatedWords': v:true,
12+
\ 'LongSentences': v:true,
13+
\ 'AnA': v:true,
14+
\ 'Spaces': v:true,
15+
\ 'SpelledNumbers': v:false,
16+
\ 'WrongQuotes': v:false,
17+
\ },
18+
\ },
19+
\})
20+
21+
call ale#linter#Define('markdown', {
22+
\ 'name': 'harper',
23+
\ 'lsp': 'stdio',
24+
\ 'executable': 'harper-ls',
25+
\ 'command': '%e --stdio',
26+
\ 'project_root': function('ale_linters#markdown#harper#GetProjectRoot'),
27+
\ 'lsp_config': {b -> ale#Var(b, 'markdown_harper_config')},
28+
\})
29+
30+
function! ale_linters#markdown#harper#GetProjectRoot(buffer) abort
31+
return fnamemodify(bufname(a:buffer), ':p:h')
32+
endfunction

autoload/ale/lsp.vim

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,27 @@ function! ale#lsp#UpdateConfig(conn_id, buffer, config) abort
329329
return 1
330330
endfunction
331331

332+
function! ale#lsp#GetConnectionConfig(conn_id) abort
333+
let l:conn = get(s:connections, a:conn_id, {})
334+
335+
return get(l:conn, 'config', {})
336+
endfunction
337+
338+
" Send a JSON-RPC response to a server-initiated request (e.g. workspace/configuration).
339+
" Unlike ale#lsp#Send, which builds outgoing requests/notifications with a 'method' field,
340+
" this sends a response with 'id' + 'result' fields to reply to a request the server sent us.
341+
function! ale#lsp#SendResponse(conn_id, id, result) abort
342+
let l:conn = get(s:connections, a:conn_id, {})
343+
344+
if empty(l:conn)
345+
return
346+
endif
347+
348+
let l:body = json_encode({'jsonrpc': '2.0', 'id': a:id, 'result': a:result})
349+
let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body
350+
call s:SendMessageData(l:conn, l:data)
351+
endfunction
352+
332353
function! ale#lsp#CallInitCallbacks(conn_id) abort
333354
let l:conn = get(s:connections, a:conn_id, {})
334355

autoload/ale/lsp_linter.vim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@ function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
241241
\ : a:response.result.items
242242

243243
call ale#lsp_linter#HandleLSPDiagnostics(a:conn_id, l:uri, l:diagnostics)
244+
elseif l:method is# 'workspace/configuration'
245+
let l:items = get(get(a:response, 'params', {}), 'items', [])
246+
let l:config = ale#lsp#GetConnectionConfig(a:conn_id)
247+
call ale#lsp#SendResponse(a:conn_id, a:response.id, map(copy(l:items), 'l:config'))
244248
elseif l:method is# 'window/showMessage'
245249
call ale#lsp_window#HandleShowMessage(
246250
\ s:lsp_linter_map[a:conn_id].name,

doc/ale-markdown.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,35 @@ dprint *ale-markdown-dprint*
1414
See |ale-dprint-options| and https://dprint.dev/plugins/markdown
1515

1616

17+
===============================================================================
18+
harper *ale-markdown-harper*
19+
20+
*ale-options.markdown_harper_config*
21+
*g:ale_markdown_harper_config*
22+
*b:ale_markdown_harper_config*
23+
markdown_harper_config
24+
g:ale_markdown_harper_config
25+
Type: |Dictionary|
26+
Default: `{'harper-ls': {'diagnosticSeverity': 'hint', 'dialect': 'American', ...}}`
27+
28+
Dictionary passed to harper-ls as LSP workspace configuration. The default
29+
enables spell check, sentence capitalization, repeated words, long
30+
sentences, a/an errors, and spacing rules, and disables spelled-out numbers
31+
and wrong-quote checks.
32+
33+
Example: >
34+
let g:ale_markdown_harper_config = {
35+
\ 'harper-ls': {
36+
\ 'diagnosticSeverity': 'warning',
37+
\ 'linters': {
38+
\ 'SpellCheck': v:true,
39+
\ 'LongSentences': v:false,
40+
\ },
41+
\ },
42+
\}
43+
<
44+
45+
1746
===============================================================================
1847
markdownlint *ale-markdown-markdownlint*
1948

doc/ale-supported-languages-and-tools.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ Notes:
404404
* Markdown
405405
* `alex`
406406
* `cspell`
407+
* `harper`
407408
* `languagetool`!!
408409
* `markdownlint`!!
409410
* `marksman`

doc/ale.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3738,6 +3738,7 @@ documented in additional help files.
37383738
markdown................................|ale-markdown-options|
37393739
cspell................................|ale-markdown-cspell|
37403740
dprint................................|ale-markdown-dprint|
3741+
harper................................|ale-markdown-harper|
37413742
markdownlint..........................|ale-markdown-markdownlint|
37423743
marksman..............................|ale-markdown-marksman|
37433744
mdl...................................|ale-markdown-mdl|

supported-tools.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ formatting.
414414
* Markdown
415415
* [alex](https://github.com/get-alex/alex)
416416
* [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell)
417+
* [harper](https://github.com/elijah-potter/harper) :speech_balloon:
417418
* [languagetool](https://languagetool.org/) :floppy_disk: :speech_balloon:
418419
* [markdownlint](https://github.com/DavidAnson/markdownlint) :floppy_disk:
419420
* [marksman](https://github.com/artempyanykh/marksman) :speech_balloon:
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Before:
2+
call ale#assert#SetUpLinterTest('markdown', 'harper')
3+
4+
After:
5+
call ale#assert#TearDownLinterTest()
6+
7+
Execute(The default command should be correct):
8+
AssertLinter 'harper-ls', ale#Escape('harper-ls') . ' --stdio'
9+
10+
Execute(Should accept configuration settings):
11+
AssertLSPConfig g:ale_markdown_harper_config
12+
13+
let b:ale_markdown_harper_config = {'harper-ls': {'diagnosticSeverity': 'warning'}}
14+
AssertLSPConfig {'harper-ls': {'diagnosticSeverity': 'warning'}}

test/lsp/test_engine_lsp_response_handling.vader

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,34 @@ Execute(LSP pull model diagnostic responses that are 'unchanged' should be handl
534534
\ g:ale_buffer_info[bufnr('')].loclist
535535
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
536536

537+
Execute(workspace/configuration requests should be answered with the connection config):
538+
let g:sent_responses = []
539+
540+
function! ale#lsp#GetConnectionConfig(conn_id) abort
541+
return {'foo': 'bar'}
542+
endfunction
543+
544+
function! ale#lsp#SendResponse(conn_id, id, result) abort
545+
call add(g:sent_responses, [a:conn_id, a:id, a:result])
546+
endfunction
547+
548+
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'pylsp', 'aliases': [], 'lsp': 'stdio'}})
549+
call ale#lsp_linter#HandleLSPResponse(1, {
550+
\ 'jsonrpc': '2.0',
551+
\ 'id': 7,
552+
\ 'method': 'workspace/configuration',
553+
\ 'params': {
554+
\ 'items': [{'section': 'foo'}, {'section': 'bar'}],
555+
\ },
556+
\})
557+
558+
AssertEqual
559+
\ [[1, 7, [{'foo': 'bar'}, {'foo': 'bar'}]]],
560+
\ g:sent_responses
561+
562+
unlet! g:sent_responses
563+
runtime autoload/ale/lsp.vim
564+
537565
Execute(LSP errors should be logged in the history):
538566
call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'foobar', 'aliases': [], 'lsp': 'stdio'}})
539567
call ale#lsp_linter#HandleLSPResponse(347, {

test/lsp/test_update_config.vader

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
Before:
22
runtime autoload/ale/lsp.vim
3+
runtime autoload/ale/job.vim
34

45
let g:conn_id = ale#lsp#Register('executable', '/foo/bar', '', {})
6+
let g:sent_data = []
57

6-
" Stub out this function, so we test updating configs.
8+
" Stub out these functions to capture calls without side effects.
79
function! ale#lsp#Send(conn_id, message) abort
810
endfunction
911

12+
function! ale#job#SendRaw(job_id, data) abort
13+
call add(g:sent_data, a:data)
14+
endfunction
15+
1016
After:
1117
Restore
1218

1319
unlet! g:conn_id
20+
unlet! g:conn
21+
unlet! g:sent_data
22+
unlet! g:remainder
23+
unlet! g:messages
1424

1525
runtime autoload/ale/lsp.vim
1626

@@ -19,3 +29,27 @@ Execute(Only send updates when the configuration dictionary changes):
1929
AssertEqual 1, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {'a': 1})
2030
AssertEqual 0, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {'a': 1})
2131
AssertEqual 1, ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {})
32+
33+
Execute(ale#lsp#GetConnectionConfig() should return empty dict for unknown connections):
34+
AssertEqual {}, ale#lsp#GetConnectionConfig('unknown:conn')
35+
36+
Execute(ale#lsp#GetConnectionConfig() should return the current connection config):
37+
call ale#lsp#UpdateConfig(g:conn_id, bufnr(''), {'foo': 'bar'})
38+
AssertEqual {'foo': 'bar'}, ale#lsp#GetConnectionConfig(g:conn_id)
39+
40+
Execute(ale#lsp#SendResponse() should do nothing for unknown connections):
41+
" Should not throw
42+
call ale#lsp#SendResponse('unknown:conn', 1, [])
43+
AssertEqual [], g:sent_data
44+
45+
Execute(ale#lsp#SendResponse() should send a JSON-RPC response message):
46+
" Give the connection a job_id so s:SendMessageData routes to ale#job#SendRaw
47+
let g:conn = ale#lsp#GetConnections()[g:conn_id]
48+
let g:conn.job_id = 1
49+
50+
call ale#lsp#SendResponse(g:conn_id, 42, ['result_value'])
51+
52+
AssertEqual 1, len(g:sent_data)
53+
let [g:remainder, g:messages] = ale#lsp#ReadMessageData(g:sent_data[0])
54+
AssertEqual '', g:remainder
55+
AssertEqual [{'jsonrpc': '2.0', 'id': 42, 'result': ['result_value']}], g:messages

0 commit comments

Comments
 (0)