3 files changed,
81 insertions(+),
30 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-09-10 13:33:34 +0300
Authored at:
2026-09-09 14:23:14 +0300
Change ID:
xknxsyqrrlnvzywnpkvkmlqyxlktwlwv
Parent:
e12aa47
M
internal/lsp/testdata/completion-contexts.txtar
··· 143 143 expenses:food 144 144 expenses:taxi 145 145 23:20 commodity "$" 146 - $ 147 146 24:19 commodity "" 147 + USD 148 148 $ 149 - USD 150 149 25:20 commodity "U" 151 150 USD 152 151 26:21 none "" ··· 160 159 acme 161 160 x 162 161 31:31 tag-value "ac" 163 - ac 164 162 acme 165 163 32:20 tag-value "ac" 166 - ac 167 164 acme 168 165 33:21 tag-value "https://exa" 169 166 https://example ··· 284 281 110:12 date "2024-01-15" 285 282 2024-01-15 286 283 111:13 commodity "" 287 - $ 288 284 USD 285 + $ 289 286 112:14 commodity "U" 290 287 USD 291 288 113:24 commodity "U" 292 289 USD 293 290 116:22 commodity "" 294 - $ 295 291 USD 292 + $ 296 293 117:21 none "" 297 294 118:18 none "" 298 295 119:22 commodity "" 299 - $ 300 296 USD 297 + $ 301 298 120:23 commodity "€"
M
internal/lsp/testdata/completion-journal.txtar
··· 9 9 assets:cash 10 10 11 11 account assets:cash 12 +account assets:bank 13 + 14 +2024-01-15 15 + assets:b $10 16 + assets:cash 17 + 18 +2024-01-15 19 + assets:b $10 20 + assets:cash 21 + 22 +2024-01-15 23 + assets:b $10 24 + assets:cash 25 + 26 +2024-01-15 27 + assets:bank $10 28 + assets:cash 29 + 30 +2024-01-16 31 + assets:b^ank $10 32 + assets:cash 33 + 34 +2024-01-15 35 + liabilities:l $10 36 + assets:cash 37 + 38 +2024-01-15 39 + liabilities:l $10 40 + assets:cash 41 + 42 +2024-01-15 43 + liabilities:l $10 44 + assets:cash 45 + 46 +2024-01-15 47 + liabilities:loan $10 48 + assets:cash 49 + 50 +2024-01-16 51 + liabilities:l^oan $10 52 + assets:cash 12 53 13 54 commodity USD 14 55 ··· 66 107 tag 客^户 67 108 68 109 -- expect -- 69 -19:10 tag-value "a" 110 +29:10 account "assets:b" 111 + assets:bank 112 +49:15 account "liabilities:l" 113 + liabilities:loan 114 +60:10 tag-value "a" 70 115 acme 71 -20:10 tag-value "" 116 +61:10 tag-value "" 72 117 alpha 73 -22:11 payee "" 118 +63:11 payee "" 74 119 Grocery 75 120 Продукти 76 121 Супермаркет 77 122 Store 78 123 sup 79 -23:12 account "expenses:f" 124 +64:12 account "expenses:f" 80 125 expenses:food 81 -28:16 account "assets:c" 126 +69:16 account "assets:c" 82 127 assets:cash 83 -30:11 commodity "U" 128 +71:11 commodity "U" 84 129 USD 85 -32:8 payee "Gr" 130 +73:8 payee "Gr" 86 131 Grocery 87 -34:7 tag "cli" 132 +75:7 tag "cli" 88 133 client 89 -36:5 tag "cli" 134 +77:5 tag "cli" 90 135 client 91 -37:6 tag "proj" 136 +78:6 tag "proj" 92 137 project 93 -39:3 directive "acc" 138 +80:3 directive "acc" 94 139 account 95 -51:16 payee "Супер" 140 +92:16 payee "Супер" 96 141 Супермаркет 97 -52:13 account "Витрати:Про" 142 +93:13 account "Витрати:Про" 98 143 Витрати:Продукти 99 -55:14 payee "sup" 144 +96:14 payee "sup" 100 145 Супермаркет 101 - sup 102 -57:15 payee "Прод" 146 +98:15 payee "Прод" 103 147 Продукти 104 -58:12 account "Витрати:Тр" 148 +99:12 account "Витрати:Тр" 105 149 Витрати:Транспорт 106 -62:11 commodity "¥" 150 +103:11 commodity "¥" 107 151 ¥ 108 -64:5 tag "客" 152 +105:5 tag "客" 109 153 客户
M
internal/lsp/textdocument_completion.go
··· 369 369 label string 370 370 score float64 371 371 count int 372 + declared bool // has a declaration directive (account/payee/commodity/tag); sorts before usage-only names 373 + exact bool // label equals the typed pattern; phantom exact names are dropped entirely 372 374 lastUsedDays int64 // days since 1970-01-01; 0 when unset 373 375 rank int // lower sorts first among equal scores; 0 except for date completions 374 376 } ··· 392 394 kind = protocol.CompletionItemKindClass 393 395 cands = make([]cmplCand, 0, len(a.Accounts)) 394 396 for name, info := range a.Accounts { 395 - cands = append(cands, cmplCand{label: name, count: info.UsedCount, lastUsedDays: dateToDays(info.LastUsed)}) 397 + cands = append(cands, cmplCand{label: name, count: info.UsedCount, lastUsedDays: dateToDays(info.LastUsed), declared: len(info.Directives) > 0}) 396 398 } 397 399 case cmplPayee: 398 400 kind = protocol.CompletionItemKindVariable 399 401 cands = make([]cmplCand, 0, len(a.Payees)) 400 402 for name, info := range a.Payees { 401 - cands = append(cands, cmplCand{label: name, count: info.UsedCount, lastUsedDays: dateToDays(info.LastUsed)}) 403 + cands = append(cands, cmplCand{label: name, count: info.UsedCount, lastUsedDays: dateToDays(info.LastUsed), declared: len(info.Directives) > 0}) 402 404 } 403 405 case cmplCommodity: 404 406 kind = protocol.CompletionItemKindValue 405 407 cands = make([]cmplCand, 0, len(a.Commodities)) 406 408 for name, info := range a.Commodities { 407 - cands = append(cands, cmplCand{label: name, count: info.UsedCount, lastUsedDays: dateToDays(info.LastUsed)}) 409 + cands = append(cands, cmplCand{label: name, count: info.UsedCount, lastUsedDays: dateToDays(info.LastUsed), declared: len(info.Directives) > 0}) 408 410 } 409 411 case cmplTagName: 410 412 kind = protocol.CompletionItemKindProperty 411 413 cands = make([]cmplCand, 0, len(a.Tags)) 412 414 for name, info := range a.Tags { 413 - cands = append(cands, cmplCand{label: name, count: info.UsedCount, lastUsedDays: dateToDays(info.LastUsed)}) 415 + cands = append(cands, cmplCand{label: name, count: info.UsedCount, lastUsedDays: dateToDays(info.LastUsed), declared: len(info.Directives) > 0}) 414 416 } 415 417 case cmplTagValue: 416 418 kind = protocol.CompletionItemKindProperty ··· 467 469 } 468 470 } 469 471 ranked := cands[:0] 472 + dropExact := ctx == cmplAccount || ctx == cmplPayee || ctx == cmplCommodity || ctx == cmplTagName || ctx == cmplTagValue 470 473 for i := range cands { 474 + cands[i].exact = pattern != "" && strings.EqualFold(cands[i].label, pattern) 475 + if dropExact && cands[i].exact && !cands[i].declared { 476 + continue // the typed name is not declared; re-offering it is noise 477 + } 471 478 sc := matcher.Score(cands[i].label) 472 479 if hasTransl { 473 480 sc = max(sc, translMatcher.Score(cands[i].label)) ··· 485 492 } 486 493 } 487 494 sort.Slice(ranked, func(i, j int) bool { 495 + if ranked[i].declared != ranked[j].declared { 496 + return ranked[i].declared 497 + } 488 498 if ranked[i].score != ranked[j].score { 489 499 return ranked[i].score > ranked[j].score 490 500 }