Skip to content

Commit eb65068

Browse files
committed
feat: have an ability to choose between transform or position property
This will affect smoothness of the cursor move and its display. Using transform will have more smoothly moving transition, but it will appear blurly.
1 parent e1e2ed0 commit eb65068

File tree

4 files changed

+54
-24
lines changed

4 files changed

+54
-24
lines changed

main.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import { App, MarkdownView, Plugin, WorkspaceLeaf } from "obsidian";
33
import { hookCursorPlugin, patchCursorPlugin, unpatchCursorPlugin } from "src/core";
44
import { AnimatedCursorSettingTab } from "src/setting-tab";
55

6-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
7-
interface AnimatedCursorSettings {}
6+
export interface AnimatedCursorSettings {
7+
useTransform: boolean;
8+
}
89

9-
export const DEFAULT_SETTINGS: AnimatedCursorSettings = {}
10+
export const DEFAULT_SETTINGS: AnimatedCursorSettings = {
11+
useTransform: true
12+
}
1013

1114
function _iterMarkdownView(app: App, callback: (view: MarkdownView) => unknown): void {
1215
app.workspace.getLeavesOfType("markdown").forEach(leaf => {
@@ -29,7 +32,7 @@ export default class AnimatedCursorPlugin extends Plugin {
2932
async onload(): Promise<void> {
3033
await this.loadSettings();
3134

32-
// this.addSettingTab(new SmoothCursorSettingTab(this.app, this));
35+
this.addSettingTab(new AnimatedCursorSettingTab(this.app, this));
3336

3437
let mdView = this.app.workspace.getActiveViewOfType(MarkdownView);
3538
if (mdView)
@@ -78,7 +81,7 @@ export default class AnimatedCursorPlugin extends Plugin {
7881
if (!cursorPlugin) return;
7982

8083
this.targetLayerConfig = cursorPlugin.layer;
81-
this.originalLayerConfig = patchCursorPlugin(cursorPlugin);
84+
this.originalLayerConfig = patchCursorPlugin(cursorPlugin, this.settings);
8285
this.alreadyPatched = true;
8386

8487
// Detach the handler after a successful attemp.

src/core.ts

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { SelectionRange } from "@codemirror/state";
22
import { Direction, EditorView, LayerConfig, LayerMarker, MeasureRequest, PluginInstance, ViewUpdate } from "@codemirror/view";
33
import { debounce } from "obsidian";
44
import { CursorLayerView, CursorPluginInstance } from "./typing";
5+
import { AnimatedCursorSettings } from "main";
56

67
/** Ensure that it is a layer config. */
78
function _isLayerConfig(object: object): object is LayerConfig {
@@ -80,16 +81,18 @@ const _blinkDebouncer = debounce((layerEl: HTMLElement) => {
8081
*/
8182
class _CursorMarker implements LayerMarker {
8283
private className: string;
84+
private useTransform: boolean;
8385

8486
readonly left: number;
8587
readonly top: number;
8688
readonly height: number;
8789

88-
constructor(className: string, left: number, top: number, height: number) {
90+
constructor(className: string, left: number, top: number, height: number, useTransform: boolean) {
8991
this.className = className;
90-
this.left = left;
91-
this.top = top;
92-
this.height = height;
92+
this.left = Math.round(left);
93+
this.top = Math.round(top);
94+
this.height = Math.round(height);
95+
this.useTransform = useTransform;
9396
}
9497

9598
draw(): HTMLElement {
@@ -100,8 +103,10 @@ class _CursorMarker implements LayerMarker {
100103
}
101104

102105
update(cursorEl: HTMLElement, prev: _CursorMarker): boolean {
103-
if (prev.className != this.className)
104-
return false;
106+
if (
107+
prev.className != this.className ||
108+
prev.useTransform != this.useTransform
109+
) return false;
105110

106111
// Reuse previous debouncer.
107112
this.requestAdjust = prev.requestAdjust ?? this.requestAdjust;
@@ -115,7 +120,8 @@ class _CursorMarker implements LayerMarker {
115120
this.left == other.left &&
116121
this.top == other.top &&
117122
this.height == other.height &&
118-
this.className == other.className
123+
this.className == other.className &&
124+
this.useTransform == other.useTransform
119125
);
120126
}
121127

@@ -124,22 +130,30 @@ class _CursorMarker implements LayerMarker {
124130
* range, the function will use its head position as the marker
125131
* position.
126132
*/
127-
static forRange(view: EditorView, className: string, range: SelectionRange): _CursorMarker | null {
133+
static forRange(view: EditorView, className: string, range: SelectionRange, useTransform: boolean): _CursorMarker | null {
128134
let cursorPos = view.coordsAtPos(range.head, range.assoc || 1);
129135
if (!cursorPos) return null;
130136
let baseCoords = _getBaseCoords(view);
131137
return new _CursorMarker(
132138
className,
133139
cursorPos.left - baseCoords.left,
134140
cursorPos.top - baseCoords.top,
135-
cursorPos.bottom - cursorPos.top
141+
cursorPos.bottom - cursorPos.top,
142+
useTransform
136143
);
137144
}
138145

139-
/** Adjust the marker position. Should not be run in updating process. */
146+
/**
147+
* Adjust the marker position. Should not be run immediately in `update`
148+
* call, use `requestAdjust` instead.
149+
*/
140150
private adjust = (cursorEl: HTMLElement): void => {
141-
cursorEl.style.left = this.left + "px";
142-
cursorEl.style.top = this.top + "px";
151+
if (this.useTransform) {
152+
cursorEl.style.transform = `translateX(${this.left}px) translateY(${this.top}px)`;
153+
} else {
154+
cursorEl.style.left = this.left + "px";
155+
cursorEl.style.top = this.top + "px";
156+
}
143157
cursorEl.style.height = this.height + "px";
144158
}
145159

@@ -168,9 +182,9 @@ export function hookCursorPlugin(view: EditorView): CursorLayerView | null | und
168182
* Patch the cursor plugin and return the original config that can be
169183
* restored again.
170184
*
171-
* **Should only be excuted once after successful hook attemp.**
185+
* **Should not be executed again after successful hook attemp.**
172186
*/
173-
export function patchCursorPlugin(cursorPlugin: CursorLayerView): LayerConfig {
187+
export function patchCursorPlugin(cursorPlugin: CursorLayerView, settings: AnimatedCursorSettings): LayerConfig {
174188
// Store the original config.
175189
let originalConfig = Object.assign({}, cursorPlugin.layer);
176190

@@ -199,7 +213,7 @@ export function patchCursorPlugin(cursorPlugin: CursorLayerView): LayerConfig {
199213
// implemented, so the primary is able to be animated.
200214
let isPrimary = range == state.selection.main,
201215
className = "cm-cursor " + (isPrimary ? "cm-cursor-primary" : "cm-cursor-secondary"),
202-
cursorMarker = _CursorMarker.forRange(view, className, range);
216+
cursorMarker = _CursorMarker.forRange(view, className, range, settings.useTransform);
203217

204218
if (cursorMarker)
205219
cursors.push(cursorMarker);

src/setting-tab.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import AnimatedCursorPlugin from "main";
2-
import { App, PluginSettingTab } from "obsidian"
2+
import { App, PluginSettingTab, Setting } from "obsidian"
33

4-
/** _Currently not in use._ */
54
export class AnimatedCursorSettingTab extends PluginSettingTab {
65
plugin: AnimatedCursorPlugin;
76

@@ -10,7 +9,21 @@ export class AnimatedCursorSettingTab extends PluginSettingTab {
109
this.plugin = plugin;
1110
}
1211

13-
display(): void {}
12+
display(): void {
13+
new Setting(this.containerEl)
14+
.setName("Slightly more smoothly")
15+
.setDesc(
16+
"If turned on, cursor moves slightly more smoothly, especially when the user moves it continously. " +
17+
"There is a downside, the cursor appears blurly."
18+
)
19+
.addToggle(toggle => {
20+
toggle
21+
.setValue(this.plugin.settings.useTransform)
22+
.onChange(val => this.plugin.settings.useTransform = val);
23+
});
24+
25+
document.createDocumentFragment();
26+
}
1427

1528
hide(): void {
1629
// Clear all components when the tab was hidden.

styles.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ settings:
7171
animation: none !important;
7272
}
7373
&>.cm-cursor {
74-
transition-property: top, left, height;
74+
transition-property: transform, top, left;
7575
transition-duration: var(--cursor-move-speed);
7676
transition-timing-function: var(--cursor-move-easing);
7777
border-left-width: 2px;

0 commit comments

Comments
 (0)