Skip to content

Commit 1e2141e

Browse files
TYBLHQYclaude
andcommitted
chore: bump version to 1.1.0
Changes: - Remove enable/disable toggle (plugin is now always-on) - Add maxCacheEntries setting with configurable cache limit - Add real-time slider value display during drag (setInstant) - Bump minAppVersion to 1.6.6 for setInstant support - Update README config table to match current settings Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f5d6411 commit 1e2141e

10 files changed

Lines changed: 116 additions & 63 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ This plugin bundles [@chenglou/pretext](https://github.com/chenglou/pretext) (MI
4040

4141
| Setting | Default | Description |
4242
|---|---|---|
43-
| Enable justification | On | Master toggle |
4443
| Hyphenation | On | Insert soft hyphens for more even spacing |
4544
| Minimum spacing ratio | 0.50 | Lowest allowed word spacing as a fraction of normal space (0.30–0.90) |
4645
| Tight penalty threshold | 0.75 | Fraction of normal space below which the algorithm penalizes tight lines (0.50–1.00) |
46+
| Text cache size | 200 | Number of paragraphs cached to avoid remeasurement on resize (50–1000) |
4747

4848
## Compliance
4949

manifest.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"id": "pretext-justify",
33
"name": "Pretext Justify",
4-
"version": "1.0.3",
5-
"minAppVersion": "0.15.0",
4+
"version": "1.1.0",
5+
"minAppVersion": "1.6.6",
66
"description": "Optimal Knuth-Plass text justification for reading view.",
77
"author": "MYQ",
88
"isDesktopOnly": false
9-
}
9+
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-pretext-justify",
3-
"version": "1.0.3",
3+
"version": "1.1.0",
44
"description": "Knuth-Plass optimal justification for Obsidian reading view",
55
"main": "main.js",
66
"scripts": {

src/justification.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ import type {
3232
*/
3333
const _spaceCache = new Map<string, number>();
3434

35+
/**
36+
* Clear all internal measurement caches. Called on plugin unload
37+
* and when the user changes cache size settings.
38+
*/
39+
export function clearJustificationCaches(): void {
40+
_spaceCache.clear();
41+
_hyphenCache.clear();
42+
}
43+
3544
export function measureSpaceWidth(font: string): number {
3645
const cached = _spaceCache.get(font);
3746
if (cached !== undefined) return cached;

src/main.ts

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import {
55
revertToParagraph,
66
clearPrepareCache,
77
clearFontMetricsCache,
8+
setPrepareCacheMaxSize,
89
type JustifySettings,
910
} from "./renderer";
11+
import { clearCache as clearPretextCache } from "@chenglou/pretext";
1012
import { PretextJustifySettingTab, DEFAULT_SETTINGS } from "./settings";
1113

1214
// ---------------------------------------------------------------------------
@@ -61,13 +63,10 @@ export default class PretextJustifyPlugin extends Plugin {
6163
async onload(): Promise<void> {
6264
await this.loadSettings();
6365

64-
this.addSettingTab(new PretextJustifySettingTab(this.app, this));
66+
// Apply cache limit from settings
67+
setPrepareCacheMaxSize(this.settings.maxCacheEntries);
6568

66-
this.addCommand({
67-
id: "toggle-justification",
68-
name: "Toggle justification",
69-
callback: () => this.toggle(),
70-
});
69+
this.addSettingTab(new PretextJustifySettingTab(this.app, this));
7170

7271
// Markdown post-processor — runs on every rendered section
7372
this.registerMarkdownPostProcessor((el) => {
@@ -85,7 +84,6 @@ export default class PretextJustifyPlugin extends Plugin {
8584
}
8685
this._fileSwitchDebounce = window.setTimeout(() => {
8786
this._fileSwitchDebounce = null;
88-
if (!this.settings.enabled) return;
8987
this._observePreviewViews();
9088
this._scanForMissedParagraphs();
9189
this._scheduleProcessing();
@@ -135,6 +133,7 @@ export default class PretextJustifyPlugin extends Plugin {
135133
this._justified.clear();
136134
clearPrepareCache();
137135
clearFontMetricsCache();
136+
clearPretextCache();
138137
}
139138

140139
// ------------------------------------------------------------------
@@ -148,32 +147,15 @@ export default class PretextJustifyPlugin extends Plugin {
148147

149148
async saveSettings(): Promise<void> {
150149
await this.saveData(this.settings);
150+
setPrepareCacheMaxSize(this.settings.maxCacheEntries);
151151
}
152152

153153
// ------------------------------------------------------------------
154-
// Toggle / refresh
154+
// Refresh
155155
// ------------------------------------------------------------------
156156

157-
async toggle(): Promise<void> {
158-
this.settings.enabled = !this.settings.enabled;
159-
await this.saveSettings();
160-
if (this.settings.enabled) {
161-
this.refresh();
162-
} else {
163-
this._pending.clear();
164-
this._revertAll();
165-
this._justified.clear();
166-
}
167-
}
168-
169157
/** Re-justify every tracked element (used after settings change). */
170158
refresh(): void {
171-
if (!this.settings.enabled) {
172-
this._revertAll();
173-
this._justified.clear();
174-
return;
175-
}
176-
177159
const entries = Array.from(this._justified.entries());
178160

179161
if (entries.length > 0) {
@@ -204,7 +186,6 @@ export default class PretextJustifyPlugin extends Plugin {
204186
// ------------------------------------------------------------------
205187

206188
private _onScroll = (): void => {
207-
if (!this.settings.enabled) return;
208189
if (this._scrollRAF !== null) return;
209190

210191
this._scrollRAF = window.requestAnimationFrame(() => {
@@ -219,7 +200,6 @@ export default class PretextJustifyPlugin extends Plugin {
219200
// ------------------------------------------------------------------
220201

221202
private _scheduleProcessing(): void {
222-
if (!this.settings.enabled) return;
223203
if (this._fileSwitchDebounce !== null) return; // wait for file-settle window
224204
if (this._processingRAF !== null) return;
225205
if (this._pending.size === 0) return;
@@ -321,8 +301,6 @@ export default class PretextJustifyPlugin extends Plugin {
321301
* or null if justification was skipped.
322302
*/
323303
private _justifyInternal(p: HTMLElement, font: string): HTMLElement | null {
324-
if (!this.settings.enabled) return null;
325-
326304
const w = p.getBoundingClientRect().width;
327305
if (w < this.settings.minWidth) return null;
328306

@@ -339,7 +317,6 @@ export default class PretextJustifyPlugin extends Plugin {
339317
// ------------------------------------------------------------------
340318

341319
private _rejustifyAll(): void {
342-
if (!this.settings.enabled) return;
343320
if (this._justified.size === 0) return;
344321

345322
// Cooldown: if we just completed a batch pass within the last 2 s,

src/renderer.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
computeGreedyLayout,
1919
measureSpaceWidth,
2020
measureHyphenWidth,
21+
clearJustificationCaches,
2122
} from "./justification";
2223
import type { JustifiedLine } from "./types";
2324

@@ -26,8 +27,6 @@ import type { JustifiedLine } from "./types";
2627
// ---------------------------------------------------------------------------
2728

2829
export interface JustifySettings {
29-
/** Enable/disable the plugin globally */
30-
enabled: boolean;
3130
/** Enable/disable hyphenation */
3231
hyphenate: boolean;
3332
/** Use greedy algorithm as fallback */
@@ -38,15 +37,17 @@ export interface JustifySettings {
3837
tightPenaltyThreshold: number;
3938
/** Minimum paragraph width in px below which justification is skipped */
4039
minWidth: number;
40+
/** Maximum entries in the prepared-text cache (50–1000) */
41+
maxCacheEntries: number;
4142
}
4243

4344
export const DEFAULT_SETTINGS: JustifySettings = {
44-
enabled: true,
4545
hyphenate: true,
4646
greedyFallback: true,
4747
minSpacingRatio: 0.5,
4848
tightPenaltyThreshold: 0.75,
4949
minWidth: 100,
50+
maxCacheEntries: 200,
5051
};
5152

5253
// ---------------------------------------------------------------------------
@@ -66,6 +67,22 @@ interface PrepareCacheEntry {
6667
}
6768

6869
const _prepareCache = new Map<string, PrepareCacheEntry>();
70+
let _prepareCacheMaxSize = 200;
71+
72+
/**
73+
* Set the maximum number of prepared-text cache entries.
74+
* Also clears the cache if the new limit is lower than the current size.
75+
*/
76+
export function setPrepareCacheMaxSize(size: number): void {
77+
_prepareCacheMaxSize = Math.max(50, Math.min(1000, size));
78+
if (_prepareCache.size > _prepareCacheMaxSize) {
79+
let toDelete = _prepareCache.size - _prepareCacheMaxSize;
80+
for (const key of _prepareCache.keys()) {
81+
_prepareCache.delete(key);
82+
if (--toDelete <= 0) break;
83+
}
84+
}
85+
}
6986

7087
function getOrPrepare(
7188
text: string,
@@ -79,10 +96,12 @@ function getOrPrepare(
7996
_prepareCache.set(key, { prepared, font, text });
8097

8198
// Evict oldest entries when cache grows too large
82-
if (_prepareCache.size > 200) {
99+
const maxSize = _prepareCacheMaxSize;
100+
if (_prepareCache.size > maxSize) {
101+
let toDelete = _prepareCache.size - maxSize;
83102
for (const key of _prepareCache.keys()) {
84103
_prepareCache.delete(key);
85-
break;
104+
if (--toDelete <= 0) break;
86105
}
87106
}
88107

@@ -117,6 +136,7 @@ function getFontMetrics(font: string): FontMetrics {
117136

118137
export function clearFontMetricsCache(): void {
119138
_fontMetricsCache.clear();
139+
clearJustificationCaches();
120140
}
121141

122142
// ---------------------------------------------------------------------------
@@ -282,8 +302,6 @@ export function justifyParagraph(
282302
settings: JustifySettings,
283303
font: string,
284304
): HTMLElement | null {
285-
if (!settings.enabled) { return null; }
286-
287305
const maxWidth = p.getBoundingClientRect().width;
288306

289307
// Account for padding

src/settings.ts

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import type PretextJustifyPlugin from "./main";
77
import type { JustifySettings } from "./renderer";
88

99
export const DEFAULT_SETTINGS: JustifySettings = {
10-
enabled: true,
1110
hyphenate: true,
1211
greedyFallback: true,
1312
minSpacingRatio: 0.5,
1413
tightPenaltyThreshold: 0.75,
1514
minWidth: 100,
15+
maxCacheEntries: 200,
1616
};
1717

1818
export class PretextJustifySettingTab extends PluginSettingTab {
@@ -29,21 +29,6 @@ export class PretextJustifySettingTab extends PluginSettingTab {
2929

3030
// Heading intentionally omitted — plugin name is shown in sidebar
3131

32-
new Setting(containerEl)
33-
.setName("Enable justification")
34-
.setDesc(
35-
"Apply Knuth-Plass optimal justification to reading view paragraphs.",
36-
)
37-
.addToggle((toggle) =>
38-
toggle
39-
.setValue(this.plugin.settings.enabled)
40-
.onChange(async (value) => {
41-
this.plugin.settings.enabled = value;
42-
await this.plugin.saveSettings();
43-
this.plugin.refresh();
44-
}),
45-
);
46-
4732
new Setting(containerEl)
4833
.setName("Hyphenation")
4934
.setDesc(
@@ -78,10 +63,17 @@ export class PretextJustifySettingTab extends PluginSettingTab {
7863
});
7964
})
8065
.addSlider((slider) => {
66+
const val = slider.sliderEl.parentElement!.createSpan({
67+
cls: "slider-value",
68+
text: this.plugin.settings.minSpacingRatio.toFixed(2),
69+
});
70+
slider.sliderEl.parentElement!.insertBefore(val, slider.sliderEl);
8171
slider
72+
.setInstant(true)
8273
.setLimits(0.3, 0.9, 0.05)
8374
.setValue(this.plugin.settings.minSpacingRatio)
8475
.onChange(async (value) => {
76+
val.textContent = value.toFixed(2);
8577
this.plugin.settings.minSpacingRatio = value;
8678
await this.plugin.saveSettings();
8779
this.plugin.refresh();
@@ -107,14 +99,57 @@ export class PretextJustifySettingTab extends PluginSettingTab {
10799
});
108100
})
109101
.addSlider((slider) => {
102+
const val = slider.sliderEl.parentElement!.createSpan({
103+
cls: "slider-value",
104+
text: this.plugin.settings.tightPenaltyThreshold.toFixed(2),
105+
});
106+
slider.sliderEl.parentElement!.insertBefore(val, slider.sliderEl);
110107
slider
108+
.setInstant(true)
111109
.setLimits(0.5, 1.0, 0.05)
112110
.setValue(this.plugin.settings.tightPenaltyThreshold)
113111
.onChange(async (value) => {
112+
val.textContent = value.toFixed(2);
114113
this.plugin.settings.tightPenaltyThreshold = value;
115114
await this.plugin.saveSettings();
116115
this.plugin.refresh();
117116
});
118117
});
118+
119+
// -- Cache size slider --
120+
121+
new Setting(containerEl)
122+
.setName("Text cache size")
123+
.setDesc(
124+
"Number of paragraphs cached to avoid re-measurement on resize. " +
125+
"Larger values improve resize responsiveness at the cost of memory. " +
126+
`Default: ${DEFAULT_SETTINGS.maxCacheEntries}.`,
127+
)
128+
.addExtraButton((btn) => {
129+
btn.setIcon("reset")
130+
.onClick(async () => {
131+
this.plugin.settings.maxCacheEntries = DEFAULT_SETTINGS.maxCacheEntries;
132+
await this.plugin.saveSettings();
133+
this.plugin.refresh();
134+
this.display();
135+
});
136+
})
137+
.addSlider((slider) => {
138+
const val = slider.sliderEl.parentElement!.createSpan({
139+
cls: "slider-value",
140+
text: String(this.plugin.settings.maxCacheEntries),
141+
});
142+
slider.sliderEl.parentElement!.insertBefore(val, slider.sliderEl);
143+
slider
144+
.setInstant(true)
145+
.setLimits(50, 1000, 50)
146+
.setValue(this.plugin.settings.maxCacheEntries)
147+
.onChange(async (value) => {
148+
val.textContent = String(value);
149+
this.plugin.settings.maxCacheEntries = value;
150+
await this.plugin.saveSettings();
151+
this.plugin.refresh();
152+
});
153+
});
119154
}
120155
}

styles.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,16 @@
3131
word-break: normal;
3232
overflow-wrap: break-word;
3333
}
34+
35+
/*
36+
* Slider value label: shows current value inline before the slider.
37+
*/
38+
.slider-value {
39+
display: inline-block;
40+
min-width: 2.5em;
41+
text-align: right;
42+
margin-right: 0.5em;
43+
font-variant-numeric: tabular-nums;
44+
color: var(--text-muted);
45+
font-size: var(--font-ui-small);
46+
}

0 commit comments

Comments
 (0)