@commte/mdbrowse 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md CHANGED
@@ -59,12 +59,22 @@ mdb
59
59
 
60
60
  プレビュー用のタブが開き、小さな背景プロセスが動きだす。以後どの Markdown を保存しても、どのプロジェクトのものでも、そのタブに出る。止めるときは `mdb --stop`、再開はまた `mdb`
61
61
 
62
+ ログアウトや再起動で消える。macOS なら、勝手に戻ってくるようにもできる
63
+
64
+ ```sh
65
+ mdb --install-agent
66
+ ```
67
+
68
+ `~/Library/LaunchAgents` に LaunchAgent を1枚置くだけで、ログインした時点から追従が動いている。外すときは `mdb --uninstall-agent`。macOS のログイン項目には「開発元を識別できない項目」として出る。スクリプトに署名していないため
69
+
62
70
  ## 使い方
63
71
 
64
72
  ```sh
65
73
  mdb # タブを開いて、以後ずっと追従させる
66
74
  mdb --stop # 背景の追従を止める
67
75
  mdb --status # いま何が出ているかを表示する
76
+ mdb --install-agent # ログイン時に自動で始めるようにする(macOS)
77
+ mdb --uninstall-agent # それを外す
68
78
  mdb file.md # そのファイルを1回だけ変換する
69
79
  mdb -w file.md # 1つのファイルだけを前面で監視する(Ctrl-C で終了)
70
80
  mdb --path # 出力先の HTML のパスを表示する
package/README.md CHANGED
@@ -59,12 +59,22 @@ mdb
59
59
 
60
60
  That opens the preview tab and starts a small background process. Save any Markdown file from here on and it shows up in that tab, whichever project it lives in. `mdb --stop` ends it; `mdb` starts it again.
61
61
 
62
+ The process is gone after a logout or a reboot. On macOS you can have it come back on its own:
63
+
64
+ ```sh
65
+ mdb --install-agent
66
+ ```
67
+
68
+ That writes a LaunchAgent under `~/Library/LaunchAgents` and nothing else, so the sync is running from the moment you log in. `mdb --uninstall-agent` removes it. macOS lists it under Login Items as an unidentified developer — the script is not code-signed.
69
+
62
70
  ## Usage
63
71
 
64
72
  ```sh
65
73
  mdb # open the tab and keep it in sync
66
74
  mdb --stop # stop the background sync
67
75
  mdb --status # show what is being previewed
76
+ mdb --install-agent # start the sync at every login (macOS)
77
+ mdb --uninstall-agent # remove it
68
78
  mdb file.md # render one file, once
69
79
  mdb -w file.md # follow one file in the foreground (Ctrl-C to stop)
70
80
  mdb --path # print the output HTML path
package/assets/head.html CHANGED
@@ -184,10 +184,17 @@
184
184
  var THEMES = ['light', 'dark'];
185
185
  var WIDTHS = [800, 680, 960, 1200];
186
186
  var printing = false;
187
- addEventListener('beforeprint', function () { printing = true; });
188
- addEventListener('afterprint', function () { printing = false; });
189
- // 印刷がキャンセルされて afterprint が来ない場合に、止まったままにならないようにする
190
- addEventListener('visibilitychange', function () { if (!document.hidden) printing = false; });
187
+ var printTimer = null;
188
+ addEventListener('beforeprint', function () {
189
+ printing = true;
190
+ // afterprint が来ないブラウザや、途中で閉じられた場合に止まったままにならないようにする
191
+ clearTimeout(printTimer);
192
+ printTimer = setTimeout(function () { printing = false; }, 60000);
193
+ });
194
+ addEventListener('afterprint', function () {
195
+ printing = false;
196
+ clearTimeout(printTimer);
197
+ });
191
198
 
192
199
  function save() { try { localStorage.setItem('mdbrowse', JSON.stringify(s)); } catch (e) {} }
193
200
  function fontSize() { return s.fontSize || parseInt(getComputedStyle(r).getPropertyValue('--font-size')) || 16; }
@@ -257,7 +264,8 @@
257
264
  }
258
265
  heads = heads.filter(function (h) { return lv(h) <= top + 1; });
259
266
  }
260
- if (heads.length >= 3) {
267
+ try {
268
+ if (heads.length >= 3 && typeof IntersectionObserver === 'function') {
261
269
  var topLevel = Math.min.apply(null, heads.map(function (h) { return +h.tagName.slice(1); }));
262
270
  var toc = document.createElement('nav');
263
271
  toc.id = 'mdtoc';
@@ -294,6 +302,7 @@
294
302
  }, { rootMargin: '0px 0px -75% 0px' });
295
303
  heads.forEach(function (h) { io.observe(h); });
296
304
  }
305
+ } catch (e) { /* 目次が組めなくても、更新の監視は動かす */ }
297
306
 
298
307
  // スクロール位置はブラウザ標準の復元に任せる(手で保存するとカクつく)
299
308
  var lastScroll = 0;
@@ -318,6 +327,7 @@
318
327
  var stampUrl = location.pathname.replace(/\.html$/, '-stamp.js');
319
328
  var known = null;
320
329
  function checkStamp() {
330
+ if (printing) return;
321
331
  var el = document.createElement('script');
322
332
  el.src = stampUrl + '?t=' + Date.now();
323
333
  el.onload = function () {
@@ -335,11 +345,12 @@
335
345
  addEventListener('focus', function () { checkStamp(); });
336
346
  // バーを操作している間は再読み込みを止める。状態を持たずにその場で見る
337
347
  // (持つと、バーの上にポインタを置いたままウィンドウを離れたときに止まったままになる)
338
- var hoverable = !matchMedia || matchMedia('(hover: hover)').matches;
348
+ var hoverable = typeof window.matchMedia !== 'function'
349
+ || window.matchMedia('(hover: hover)').matches;
339
350
  setInterval(function () {
340
351
  if (printing || (hoverable && bar.matches(':hover'))) return;
341
352
  if (Date.now() - lastScroll < 900) return;
342
353
  checkStamp();
343
- }, 1000);
354
+ }, 250);
344
355
  });
345
356
  </script>
package/bin/mdbrowse CHANGED
@@ -3,9 +3,14 @@
3
3
  # browser tab can stay open and just swap its contents.
4
4
  set -euo pipefail
5
5
 
6
- VERSION="0.2.1"
6
+ VERSION="0.3.1"
7
7
  PROG="$(basename "$0")"
8
8
  OUT="${MDBROWSE_OUT:-/tmp/mdbrowse.html}"
9
+ case "$OUT" in
10
+ *.html) ;;
11
+ *) echo "$(basename "$0"): MDBROWSE_OUT must end with .html (got: $OUT)" >&2; exit 2 ;;
12
+ esac
13
+ STAMP="${OUT%.html}-stamp.js"
9
14
  CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/mdbrowse"
10
15
 
11
16
  # スタイルシートの探索順
@@ -40,6 +45,8 @@ Usage:
40
45
  mdb <file.md> render that file once
41
46
  mdb --stop stop the background sync
42
47
  mdb --status show what is being previewed
48
+ mdb --install-agent start the sync automatically at every login (macOS)
49
+ mdb --uninstall-agent remove it
43
50
  mdb -w <file|dir> watch in the foreground instead (Ctrl-C to stop)
44
51
  mdb --eject copy the bundled stylesheet into your config directory
45
52
  mdb --path print the output HTML path
@@ -47,7 +54,12 @@ Usage:
47
54
 
48
55
  With no arguments, mdb opens the preview tab and starts a small background
49
56
  process. From then on, whatever Markdown file you save — in any project, from
50
- any editor — shows up in that tab. Nothing else to set up. `mdb --stop` ends it.
57
+ any editor — shows up in that tab. Nothing else to set up. `mdb --stop` ends it,
58
+ and it is gone after a logout or a reboot.
59
+
60
+ `mdb --install-agent` makes it start on its own at every login, so you never
61
+ have to think about starting or stopping it. It writes a LaunchAgent under
62
+ ~/Library/LaunchAgents and nothing else; `mdb --uninstall-agent` removes it.
51
63
 
52
64
  Finding the file you just saved uses Spotlight (mdfind). Files under hidden
53
65
  directories, node_modules and ~/Library are ignored. Without Spotlight, mdb
@@ -72,14 +84,28 @@ open_url() {
72
84
  fi
73
85
  }
74
86
 
87
+ # まだ何も変換していないときの仮ページ。スタイルシートごと入れるので、
88
+ # 更新の監視も目次もバーも、ふつうのページと同じように動く
89
+ placeholder() {
90
+ printf '%s\n' '<!doctype html><meta charset="utf-8"><title>mdbrowse</title>'
91
+ [ -f "$HEAD" ] && cat "$HEAD"
92
+ printf '%s\n' '<p>No preview yet. Save a Markdown file.'
93
+ }
94
+
75
95
  open_tab() {
76
- [ -f "$OUT" ] || printf '<!doctype html><meta charset="utf-8"><p>No preview yet.' > "$OUT"
77
- [ -f "${OUT%.html}-stamp.js" ] || printf 'window.__mdbrowseStamp="0";\n' > "${OUT%.html}-stamp.js"
96
+ [ -f "$OUT" ] || placeholder > "$OUT"
97
+ [ -f "$STAMP" ] || printf 'window.__mdbrowseStamp="0";\n' > "$STAMP"
78
98
  open_url
79
99
  }
80
100
 
81
- PIDFILE="${OUT%.html}-sync.pid"
82
- LOGFILE="${OUT%.html}-sync.log"
101
+ # PID・ログ・ロックは自分だけが書ける場所に置く。共有の /tmp に固定名で置くと、
102
+ # 先に symlink を作られたときに書き込み先を差し替えられる
103
+ RUNTIME_DIR="${TMPDIR:-/tmp}/mdbrowse-$(id -u)"
104
+ ( umask 077; mkdir -p "$RUNTIME_DIR" ) 2>/dev/null || true
105
+ LOGFILE="$RUNTIME_DIR/sync.log"
106
+ LOCKDIR="$RUNTIME_DIR/sync.lock"
107
+ PIDFILE="$LOCKDIR/pid"
108
+ LEGACY_PIDFILE="${OUT%.html}-sync.pid"
83
109
 
84
110
  running_pid() {
85
111
  [ -f "$PIDFILE" ] || return 1
@@ -92,15 +118,27 @@ running_pid() {
92
118
  }
93
119
 
94
120
  stop_sync() {
95
- local pid
121
+ local pid stopped=0 i=0
96
122
  if pid="$(running_pid)"; then
97
123
  kill "$pid" 2>/dev/null || true
98
- rm -f "$PIDFILE"
99
- echo "$PROG: stopped"
100
- else
101
- rm -f "$PIDFILE"
102
- echo "$PROG: not running"
124
+ while [ $i -lt 30 ]; do
125
+ kill -0 "$pid" 2>/dev/null || break
126
+ i=$(( i + 1 ))
127
+ sleep 0.1
128
+ done
129
+ stopped=1
130
+ fi
131
+ # 0.2.x が置いた古い場所のものも拾う
132
+ if [ -f "$LEGACY_PIDFILE" ]; then
133
+ local old; old="$(cat "$LEGACY_PIDFILE" 2>/dev/null || true)"
134
+ if [ -n "$old" ] && kill -0 "$old" 2>/dev/null; then
135
+ kill "$old" 2>/dev/null || true
136
+ stopped=1
137
+ fi
138
+ rm -f "$LEGACY_PIDFILE"
103
139
  fi
140
+ rm -rf "$LOCKDIR"
141
+ if [ "$stopped" -eq 1 ]; then echo "$PROG: stopped"; else echo "$PROG: not running"; fi
104
142
  }
105
143
 
106
144
  start_sync() {
@@ -124,8 +162,74 @@ start_sync() {
124
162
  fi
125
163
  }
126
164
 
165
+ AGENT_LABEL="com.commte.mdbrowse"
166
+ AGENT_PLIST="$HOME/Library/LaunchAgents/$AGENT_LABEL.plist"
167
+
168
+ agent_installed() { [ -f "$AGENT_PLIST" ]; }
169
+
170
+ install_agent() {
171
+ if [ "$(uname -s)" != "Darwin" ]; then
172
+ echo "$PROG: --install-agent is macOS only" >&2
173
+ return 1
174
+ fi
175
+ local self; self="$(resolve_dir "$0")/$(basename "$(readlink "$0" 2>/dev/null || echo "$0")")"
176
+ [ -x "$self" ] || self="$0"
177
+
178
+ # launchd の PATH は最小限なので、pandoc と node の場所を書き込んでおく
179
+ local paths="/usr/bin:/bin:/usr/sbin:/sbin"
180
+ local d
181
+ for d in "$(command -v pandoc)" "$(command -v node)" "$(command -v mdfind)"; do
182
+ [ -n "$d" ] && paths="$(dirname "$d"):$paths"
183
+ done
184
+
185
+ mkdir -p "$HOME/Library/LaunchAgents"
186
+ {
187
+ printf '%s\n' '<?xml version="1.0" encoding="UTF-8"?>'
188
+ printf '%s\n' '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
189
+ printf '%s\n' '<plist version="1.0">'
190
+ printf '%s\n' '<dict>'
191
+ printf ' <key>Label</key><string>%s</string>\n' "$AGENT_LABEL"
192
+ printf '%s\n' ' <key>ProgramArguments</key>'
193
+ printf '%s\n' ' <array>'
194
+ printf ' <string>%s</string>\n' "$self"
195
+ printf '%s\n' ' <string>--sync-daemon</string>'
196
+ printf ' <string>%s</string>\n' "$HOME"
197
+ printf '%s\n' ' </array>'
198
+ printf '%s\n' ' <key>RunAtLoad</key><true/>'
199
+ printf '%s\n' ' <key>KeepAlive</key><false/>'
200
+ printf ' <key>StandardErrorPath</key><string>%s</string>\n' "$LOGFILE"
201
+ printf '%s\n' ' <key>EnvironmentVariables</key>'
202
+ printf '%s\n' ' <dict>'
203
+ printf ' <key>PATH</key><string>%s</string>\n' "$paths"
204
+ [ -n "${MDBROWSE_OUT:-}" ] && printf ' <key>MDBROWSE_OUT</key><string>%s</string>\n' "$MDBROWSE_OUT"
205
+ [ -n "${MDBROWSE_HEAD:-}" ] && printf ' <key>MDBROWSE_HEAD</key><string>%s</string>\n' "$MDBROWSE_HEAD"
206
+ printf '%s\n' ' </dict>'
207
+ printf '%s\n' '</dict>'
208
+ printf '%s\n' '</plist>'
209
+ } > "$AGENT_PLIST"
210
+
211
+ launchctl bootout "gui/$(id -u)/$AGENT_LABEL" 2>/dev/null || true
212
+ if ! launchctl bootstrap "gui/$(id -u)" "$AGENT_PLIST" 2>/dev/null; then
213
+ launchctl load -w "$AGENT_PLIST" 2>/dev/null || true
214
+ fi
215
+ echo "$PROG: starts at login now ($AGENT_PLIST)"
216
+ }
217
+
218
+ uninstall_agent() {
219
+ launchctl bootout "gui/$(id -u)/$AGENT_LABEL" 2>/dev/null \
220
+ || launchctl unload -w "$AGENT_PLIST" 2>/dev/null || true
221
+ if [ -f "$AGENT_PLIST" ]; then
222
+ rm -f "$AGENT_PLIST"
223
+ echo "$PROG: will not start at login any more"
224
+ else
225
+ echo "$PROG: not installed"
226
+ fi
227
+ }
228
+
127
229
  case "${1:-}" in
128
230
  -h|--help) usage; exit 0 ;;
231
+ --install-agent) install_agent; exit $? ;;
232
+ --uninstall-agent) uninstall_agent; exit 0 ;;
129
233
  -v|--version) echo "mdbrowse $VERSION"; exit 0 ;;
130
234
  --path) echo "$OUT"; exit 0 ;;
131
235
  --stop) stop_sync; exit 0 ;;
@@ -135,6 +239,11 @@ case "${1:-}" in
135
239
  else
136
240
  echo "$PROG: not running"
137
241
  fi
242
+ if agent_installed; then
243
+ echo "starts at login: yes ($AGENT_PLIST)"
244
+ else
245
+ echo "starts at login: no (mdb --install-agent to change that)"
246
+ fi
138
247
  [ -f "$OUT" ] && echo "showing: $(grep -o '<title>[^<]*' "$OUT" 2>/dev/null | sed 's/<title>//')"
139
248
  exit 0 ;;
140
249
  --eject)
@@ -228,13 +337,18 @@ else
228
337
  fi
229
338
 
230
339
  render() {
231
- # 途中経過をタブに見せないため、別名で組み立ててから置き換える
232
- local tmp="$OUT.part"
340
+ # 途中経過をタブに見せないため、別名で組み立ててから置き換える。
341
+ # 名前は毎回変える。固定名だと、同時に走ったときに互いの中間結果を踏む
342
+ local tmp
343
+ tmp="$(mktemp "$OUT.part.XXXXXX")" || return 1
344
+
233
345
  # 出力先が .part なので、拡張子から形式を推測させず明示する
234
346
  local args=(--standalone --from gfm --to html5 "${hl[@]}" --variable "pagetitle=$(basename "$src")" --output "$tmp")
235
347
  [ -f "$HEAD" ] && args+=(--include-in-header "$HEAD")
236
348
 
237
- pandoc "$src" "${args[@]}"
349
+ # 途中で失敗したら、そこで止めて古い表示を残す。
350
+ # 関数を `render || ...` の形で呼ぶと関数の中では set -e が効かないので、各段で判定する
351
+ pandoc "$src" "${args[@]}" || { rm -f "$tmp"; return 1; }
238
352
 
239
353
  # コードブロックを Shiki で色付けし直す。失敗しても変換自体は成立させる
240
354
  if [ "$use_shiki" -eq 1 ]; then
@@ -243,14 +357,15 @@ render() {
243
357
 
244
358
  # frontmatter の title を pandoc が拾うと本文の先頭に見出しが増えるので落とす。
245
359
  # ブラウザのタブ名には pagetitle を使っている
246
- perl -0pi -e 's#<header id="title-block-header">.*?</header>\n?##s' "$tmp"
360
+ perl -0pi -e 's#<header id="title-block-header">.*?</header>\n?##s' "$tmp" \
361
+ || { rm -f "$tmp"; return 1; }
247
362
 
248
363
  # 出力先が /tmp なので、元ファイルからの相対パス(画像・ローカルリンク)が
249
364
  # そのままでは解決できない。ソースのあるディレクトリ基準の file:// に書き換える。
250
365
  # 書き換えるのはタグの属性だけ。本文中の src="..." のようなインラインコードは触らない。
251
366
  # スキーム付き(http(s) data: mailto: など)/絶対パス/ページ内アンカーはそのまま残す
252
367
  local src_dir
253
- src_dir="$(cd "$(dirname "$src")" && pwd)" || return 1
368
+ src_dir="$(cd "$(dirname "$src")" && pwd)" || { rm -f "$tmp"; return 1; }
254
369
  MDBROWSE_SRC_DIR="$src_dir" perl -0pi -e '
255
370
  BEGIN {
256
371
  $base = $ENV{MDBROWSE_SRC_DIR};
@@ -262,21 +377,26 @@ render() {
262
377
  $base =~ s/"/%22/g;
263
378
  $base =~ s/ /%20/g;
264
379
  }
265
- s{(<(?:img|a|source|video|audio|embed|object|track)\b)([^>]*?)(/?>)}{
380
+ # 属性値の中の > でタグを切らないよう、引用符の中はまとめて食う
381
+ s{(<(?:img|a|source|video|audio|embed|object|track)\b)((?:[^>"\x27]|"[^"]*"|\x27[^\x27]*\x27)*)(>)}{
266
382
  my ($tag, $attrs, $close) = ($1, $2, $3);
267
383
  $attrs =~ s{((?:src|href|poster|data)=")(?![a-zA-Z][a-zA-Z0-9+.\-]*:|//|/|\#|")([^"]*)"}
268
384
  {$1 . "file://" . $base . "/" . $2 . "\""}ge;
385
+ $attrs =~ s{((?:src|href|poster|data)=\x27)(?![a-zA-Z][a-zA-Z0-9+.\-]*:|//|/|\#|\x27)([^\x27]*)\x27}
386
+ {$1 . "file://" . $base . "/" . $2 . "\x27"}ge;
269
387
  $tag . $attrs . $close;
270
388
  }gse;
271
- ' "$tmp"
389
+ ' "$tmp" || { rm -f "$tmp"; return 1; }
272
390
 
273
- mv -f "$tmp" "$OUT"
391
+ mv -f "$tmp" "$OUT" || { rm -f "$tmp"; return 1; }
274
392
 
275
393
  # 更新の目印。ブラウザはこれを見て、中身が変わったときだけ読み直す。
276
394
  # 本体の差し替えが済んでから書く
277
- local stamp="${OUT%.html}-stamp.js"
278
- printf 'window.__mdbrowseStamp="%s";\n' "$(date +%s)-$RANDOM" > "$stamp.part"
279
- mv -f "$stamp.part" "$stamp"
395
+ local stamp_tmp
396
+ stamp_tmp="$(mktemp "$STAMP.part.XXXXXX")" || return 1
397
+ printf 'window.__mdbrowseStamp="%s";\n' "$(date +%s)-$RANDOM" > "$stamp_tmp" \
398
+ || { rm -f "$stamp_tmp"; return 1; }
399
+ mv -f "$stamp_tmp" "$STAMP" || { rm -f "$stamp_tmp"; return 1; }
280
400
  }
281
401
 
282
402
  # ファイルの更新時刻とサイズ。同じ秒内の2回目の保存も拾えるようにサイズも見る
@@ -311,10 +431,23 @@ newest_global() {
311
431
 
312
432
  # 背景で動く本体。保存された Markdown を追いかけて変換し続ける
313
433
  if [ "$daemon" -eq 1 ]; then
314
- # 先に別のものが動いていたら黙って降りる(同時に叩かれた場合の取り合いを避ける)
315
- if running_pid >/dev/null; then exit 0; fi
434
+ # 確認と取得を1操作にする。mkdir は原子的なので、同時に叩かれても1つしか通らない
435
+ if ! mkdir "$LOCKDIR" 2>/dev/null; then
436
+ # 取れなかった側は、持ち主が名乗るのを少し待つ。
437
+ # すぐ「持ち主なし」と判断すると、書き込み前の相手からロックを奪ってしまう
438
+ i=0
439
+ while [ $i -lt 30 ]; do
440
+ running_pid >/dev/null && exit 0
441
+ i=$(( i + 1 ))
442
+ sleep 0.1
443
+ done
444
+ # 3秒待っても名乗らないなら、置き去りのロックとして回収する
445
+ rm -rf "$LOCKDIR"
446
+ mkdir "$LOCKDIR" 2>/dev/null || exit 0
447
+ fi
316
448
  echo $$ > "$PIDFILE"
317
- trap 'rm -f "$PIDFILE"' EXIT
449
+ # 自分が持っているときだけ外す。あとから起きたものの分を消さないため
450
+ trap 'if [ "$(cat "$PIDFILE" 2>/dev/null)" = "$$" ]; then rm -rf "$LOCKDIR"; fi' EXIT
318
451
  use_spotlight=0
319
452
  command -v mdfind >/dev/null 2>&1 && use_spotlight=1
320
453
  if [ "$use_spotlight" -eq 0 ]; then root="$sync_cwd"; fi
@@ -326,16 +459,18 @@ if [ "$daemon" -eq 1 ]; then
326
459
  # 変換の失敗は画面に出ないので、ログに残す
327
460
  log() { printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >> "$LOGFILE"; }
328
461
 
329
- # Spotlight を使えない場合は木を歩く。大きな木では間隔を伸ばす
330
- scan_gap=2
462
+ # 表示中のファイルは 0.25 秒ごとに見る。1周 = 0.25 秒
463
+ TICK=0.25
464
+ # Spotlight への問い合わせは 2 秒ごと(8周に1回)
465
+ scan_gap=8
331
466
  if [ "$use_spotlight" -eq 0 ]; then
332
467
  t0="$(perl -MTime::HiRes=time -e 'printf "%d", time*1000')"
333
468
  newest_md "$root" >/dev/null
334
469
  t1="$(perl -MTime::HiRes=time -e 'printf "%d", time*1000')"
335
- scan_gap=$(( ( (t1 - t0) * 5 + 999) / 1000 ))
336
- [ "$scan_gap" -lt 2 ] && scan_gap=2
337
- [ "$scan_gap" -gt 10 ] && scan_gap=10
338
- log "watching $root every ${scan_gap}s (no Spotlight)"
470
+ scan_gap=$(( ( (t1 - t0) * 5 + 249) / 250 ))
471
+ [ "$scan_gap" -lt 8 ] && scan_gap=8
472
+ [ "$scan_gap" -gt 40 ] && scan_gap=40
473
+ log "watching $root every $(( scan_gap / 4 ))s (no Spotlight)"
339
474
  fi
340
475
 
341
476
  src="$(pick)"
@@ -343,7 +478,7 @@ if [ "$daemon" -eq 1 ]; then
343
478
  last="$src $(fingerprint "$src") $(fingerprint "$HEAD")"
344
479
  # 開いているファイルの保存は毎秒見る。別ファイルへの切り替えの検出は2秒ごと
345
480
  tick=0
346
- while sleep 1; do
481
+ while sleep "$TICK"; do
347
482
  tick=$(( tick + 1 ))
348
483
  if [ $(( tick % scan_gap )) -eq 0 ]; then
349
484
  cand="$(pick)"
@@ -375,7 +510,7 @@ render
375
510
  if [ "$watch" -eq 1 ]; then
376
511
  # ディレクトリを見る場合、木が大きいと走査が重い。1回の走査時間から
377
512
  # 待ち時間を決めて、CPU を食い潰さないようにする
378
- interval=1
513
+ interval=0.25
379
514
  if [ -n "$root" ]; then
380
515
  t0="$(perl -MTime::HiRes=time -e 'printf "%d", time*1000')"
381
516
  newest_md "$root" >/dev/null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commte/mdbrowse",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Preview the Markdown file you are editing in a real browser, with your own CSS, from any editor that can run a shell command. No server, no port.",
5
5
  "bin": {
6
6
  "mdbrowse": "bin/mdbrowse",