1919
2020function source :enabled () return true end
2121
22- function source . get_trigger_characters ()
22+ function source : get_trigger_characters ()
2323 return { ' @' , ' .' , ' (' , ' [' , ' :' , ' {' }
2424end
2525
@@ -44,6 +44,94 @@ local function prepend_to_complete_word(a, b)
4444 return a
4545end
4646
47+ local function make_cmp_context (blink_context )
48+ local self = {}
49+ local cursor
50+ if blink_context then
51+ cursor = blink_context .cursor
52+ self .cursor_line = blink_context .line
53+ else
54+ cursor = vim .api .nvim_win_get_cursor (0 )
55+ self .cursor_line = vim .api .nvim_get_current_line ()
56+ end
57+
58+ self .cursor = {}
59+ self .cursor .row = cursor [1 ]
60+ self .cursor .col = cursor [2 ] + 1
61+ self .cursor .line = self .cursor .row - 1
62+ -- self.cursor.character = require('cmp.utils.misc').to_utfindex(self.cursor_line, self.cursor.col)
63+ self .cursor_before_line = string.sub (self .cursor_line , 1 , self .cursor .col - 1 )
64+ self .cursor_after_line = string.sub (self .cursor_line , self .cursor .col )
65+ return self
66+ end
67+
68+ --- Get the context around the cursor position for code completion
69+ --- @param cmp_context table The completion context object containing cursor position and line info
70+ --- @return table Context information with the following fields :
71+ --- - lines_before: string - Text content before cursor, truncated based on context window size
72+ --- - lines_after: string - Text content after cursor, truncated based on context window size
73+ --- - opts: table - Options indicating if context was truncated:
74+ --- - is_incomplete_before: boolean - True if content before cursor was truncated
75+ --- - is_incomplete_after: boolean - True if content after cursor was truncated
76+ local function get_context (cmp_context )
77+ local context_window = 128
78+ local context_ratio = 0.75
79+
80+ local cursor = cmp_context .cursor
81+ local lines_before_list = vim .api .nvim_buf_get_lines (0 , 0 , cursor .line , false )
82+ local lines_after_list = vim .api .nvim_buf_get_lines (0 , cursor .line + 1 , - 1 , false )
83+
84+ local lines_before = table.concat (lines_before_list , ' \n ' )
85+ local lines_after = table.concat (lines_after_list , ' \n ' )
86+
87+ lines_before = lines_before .. ' \n ' .. cmp_context .cursor_before_line
88+ lines_after = cmp_context .cursor_after_line .. ' \n ' .. lines_after
89+
90+ Log .debug (' lines_before: {}' , lines_before )
91+ Log .debug (' lines_after: {}' , lines_after )
92+
93+ local n_chars_before = vim .fn .strchars (lines_before )
94+ local n_chars_after = vim .fn .strchars (lines_after )
95+
96+ local opts = {
97+ is_incomplete_before = false ,
98+ is_incomplete_after = false ,
99+ }
100+
101+ if n_chars_before + n_chars_after > context_window then
102+ -- use some heuristic to decide the context length of before cursor and after cursor
103+ if n_chars_before < context_window * context_ratio then
104+ -- If the context length before cursor does not exceed the maximum
105+ -- size, we include the full content before the cursor.
106+ lines_after = vim .fn .strcharpart (lines_after , 0 , context_window - n_chars_before )
107+ opts .is_incomplete_after = true
108+ elseif n_chars_after < context_window * (1 - context_ratio ) then
109+ -- if the context length after cursor does not exceed the maximum
110+ -- size, we include the full content after the cursor.
111+ lines_before = vim .fn .strcharpart (lines_before , n_chars_before + n_chars_after - context_window )
112+ opts .is_incomplete_before = true
113+ else
114+ -- at the middle of the file, use the context_ratio to determine the allocation
115+ lines_after =
116+ vim .fn .strcharpart (lines_after , 0 , math.floor (context_window * (1 - context_ratio )))
117+
118+ lines_before = vim .fn .strcharpart (
119+ lines_before ,
120+ n_chars_before - math.floor (context_window * context_ratio )
121+ )
122+
123+ opts .is_incomplete_before = true
124+ opts .is_incomplete_after = true
125+ end
126+ end
127+
128+ return {
129+ lines_before = lines_before ,
130+ lines_after = lines_after ,
131+ opts = opts ,
132+ }
133+ end
134+
47135--- @param ctx blink.cmp.Context
48136function source :get_completions (ctx , callback )
49137 -- ctx (context) contains the current keyword, cursor position, bufnr, etc.
@@ -64,8 +152,10 @@ function source:get_completions(ctx, callback)
64152 return
65153 end
66154
155+ local context = get_context (make_cmp_context (ctx ))
156+
67157 generated_text = vim .tbl_map (function (item )
68- return prepend_to_complete_word (item , ctx .lines_before )
158+ return prepend_to_complete_word (item , context .lines_before )
69159 end , generated_text )
70160
71161 local max_label_width = 60
@@ -94,14 +184,13 @@ function source:get_completions(ctx, callback)
94184 },
95185 })
96186 end
97- callback {
187+ Log .debug (' items: {}' , items )
188+ callback ({
98189 is_incomplete_forward = false ,
99190 is_incomplete_backward = false ,
100191 items = items ,
101- }
192+ })
102193 end )
103-
104- return function () end
105194end
106195
107196return source
0 commit comments