editor: Fix double $ sign on completion accept in PHP (#34726)

Closes #33510 https://github.com/zed-extensions/php/issues/29

If certain language servers do not provide an insert/replace range, we
use `surrounding_word` as a fallback for that range, which internally
uses `word_characters`. It makes sense to use
`completion_query_characters` instead of `word_characters` to get that
range, because we use `completion_query_characters` to query completions
in the first place.

That means, for some hypothetical reason (e.g., if the Tailwind server
stops providing insert/replace ranges), we would correctly fall back to
the range "bg-blue-200^" instead of "200^", because
`completion_query_characters` includes "-" in this case.

For this particular fix, right now the default PHP language server
`phpactor` does not provide an insert/replace range, and hence
completion query character is used, which is `$` in this case.

Note that `$` isn't in word characters for reasons mentioned here:
https://github.com/zed-extensions/php/issues/14

Release Notes:

- Fixed an issue where accepting variable completion in PHP would result
in a double $ sign in the prefix.
This commit is contained in:
Smit Barmase 2025-07-18 22:39:00 +05:30 committed by GitHub
parent 8bc8d61fa6
commit 1dd470ca48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 14 additions and 8 deletions

View file

@ -3364,13 +3364,19 @@ impl BufferSnapshot {
/// Returns a tuple of the range and character kind of the word
/// surrounding the given position.
pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
pub fn surrounding_word<T: ToOffset>(
&self,
start: T,
for_completion: bool,
) -> (Range<usize>, Option<CharKind>) {
let mut start = start.to_offset(self);
let mut end = start;
let mut next_chars = self.chars_at(start).take(128).peekable();
let mut prev_chars = self.reversed_chars_at(start).take(128).peekable();
let classifier = self.char_classifier_at(start);
let classifier = self
.char_classifier_at(start)
.for_completion(for_completion);
let word_kind = cmp::max(
prev_chars.peek().copied().map(|c| classifier.kind(c)),
next_chars.peek().copied().map(|c| classifier.kind(c)),