From 62b173a38d5b0eac8721860d120e3a202aa1e9a1 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 14 Nov 2024 13:08:36 +0000 Subject: [PATCH 1/2] Allow tab completing users in brackets Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/autocomplete/UserProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx index 18c93d0cd03..a8f50ceccbe 100644 --- a/src/autocomplete/UserProvider.tsx +++ b/src/autocomplete/UserProvider.tsx @@ -37,7 +37,7 @@ const USER_REGEX = /\B@\S*/g; // used when you hit 'tab' - we allow some separator chars at the beginning // to allow you to tab-complete /mat into /(matthew) -const FORCED_USER_REGEX = /[^/,:; \t\n]\S*/g; +const FORCED_USER_REGEX = /[^/,.():; \t\n]\S*/g; export default class UserProvider extends AutocompleteProvider { public matcher: QueryMatcher; From 572afd72903af25ebae9a03d457b5dde06aa23e2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 14 Nov 2024 13:09:08 +0000 Subject: [PATCH 2/2] Account for range offsets when tab completing to not replace unrelated characters Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/editor/autocomplete.ts | 4 +++- src/editor/model.ts | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/editor/autocomplete.ts b/src/editor/autocomplete.ts index 28f86ddf779..542a2bbea51 100644 --- a/src/editor/autocomplete.ts +++ b/src/editor/autocomplete.ts @@ -10,11 +10,12 @@ import { KeyboardEvent } from "react"; import { Part, CommandPartCreator, PartCreator } from "./parts"; import DocumentPosition from "./position"; -import { ICompletion } from "../autocomplete/Autocompleter"; +import { ICompletion, ISelectionRange } from "../autocomplete/Autocompleter"; import Autocomplete from "../components/views/rooms/Autocomplete"; export interface ICallback { replaceParts?: Part[]; + range?: ISelectionRange; close?: boolean; } @@ -82,6 +83,7 @@ export default class AutocompleteWrapperModel { this.updateCallback({ replaceParts: this.partForCompletion(completion), close: true, + range: completion.range, }); } diff --git a/src/editor/model.ts b/src/editor/model.ts index 67b19a3999a..efe294cd214 100644 --- a/src/editor/model.ts +++ b/src/editor/model.ts @@ -250,14 +250,24 @@ export default class EditorModel { return Promise.resolve(); } - private onAutoComplete = ({ replaceParts, close }: ICallback): void => { + private onAutoComplete = ({ replaceParts, close, range }: ICallback): void => { let pos: DocumentPosition | undefined; if (replaceParts) { const autoCompletePartIdx = this.autoCompletePartIdx || 0; - this._parts.splice(autoCompletePartIdx, this.autoCompletePartCount, ...replaceParts); + + this.replaceRange( + new DocumentPosition(autoCompletePartIdx, range?.start ?? 0), + new DocumentPosition( + autoCompletePartIdx + this.autoCompletePartCount - 1, + range?.end ?? this.parts[autoCompletePartIdx + this.autoCompletePartCount - 1].text.length, + ), + replaceParts, + ); + this.autoCompletePartCount = replaceParts.length; const lastPart = replaceParts[replaceParts.length - 1]; - const lastPartIndex = autoCompletePartIdx + replaceParts.length - 1; + // `replaceRange` merges adjacent parts so we need to find it in the new parts list + const lastPartIndex = this.parts.indexOf(lastPart); pos = new DocumentPosition(lastPartIndex, lastPart.text.length); } if (close) {