diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx
index 18c93d0cd0..a8f50ceccb 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<RoomMember>;
diff --git a/src/editor/autocomplete.ts b/src/editor/autocomplete.ts
index 28f86ddf77..542a2bbea5 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 67b19a3999..efe294cd21 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) {