newsline-cli 1.0.1 β 1.0.3
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.md +8 -1
- package/install.sh +26 -0
- package/newsline +70 -8
- package/package.json +1 -1
- package/readme/ko.md +1 -0
- package/refresh.sh +1 -1
- package/statusline.sh +18 -0
package/README.md
CHANGED
|
@@ -71,6 +71,7 @@ Re-run `newsline init`, or edit `~/.config/newsline/config.json`:
|
|
|
71
71
|
| `maxlen` | `120` | max characters (`max` = no cut) |
|
|
72
72
|
| `icon` | `π°` | leading glyph (`none` to hide) |
|
|
73
73
|
| `color` | `magenta` | headline color: `default` `gray` `white` `cyan` `yellow` `green` `blue` `magenta` `red` |
|
|
74
|
+
| `clickhint` | `auto` | click-modifier hint before the headline (`auto` per terminal, `off` to hide, or custom text) |
|
|
74
75
|
|
|
75
76
|
Set one directly with `newsline color <name>` (e.g. `newsline color gray`), or run
|
|
76
77
|
`newsline color` with no name to step to the next color (default β gray β white β cyan β
|
|
@@ -98,7 +99,13 @@ Claude Code plugin: run `/plugin marketplace update itdar`, then `/reload-plugin
|
|
|
98
99
|
## Uninstall
|
|
99
100
|
|
|
100
101
|
```sh
|
|
101
|
-
newsline uninstall
|
|
102
|
+
newsline uninstall # restores your previous status line
|
|
103
|
+
newsline uninstall --purge # also removes the CLI binary + the PATH line install.sh added
|
|
102
104
|
```
|
|
103
105
|
|
|
104
106
|
Needs `bash` + `python3` (macOS / Linux; Windows via WSL).
|
|
107
|
+
|
|
108
|
+
## Contributing
|
|
109
|
+
|
|
110
|
+
Bug reports and PRs welcome β see [CONTRIBUTING.md](CONTRIBUTING.md) for local setup,
|
|
111
|
+
testing, and the release process.
|
package/install.sh
CHANGED
|
@@ -34,6 +34,32 @@ ln -sf "$SHARE/newsline" "$BIN/newsline"
|
|
|
34
34
|
|
|
35
35
|
echo "β installed: $BIN/newsline"
|
|
36
36
|
|
|
37
|
+
# Garbage-collect stale PATH lines from earlier installs whose prefix no longer
|
|
38
|
+
# exists (e.g. throwaway test prefixes), so rc files don't pile up dead newsline
|
|
39
|
+
# entries that shadow the current install. Only drops blocks whose dir is gone.
|
|
40
|
+
prune_stale_newsline_path() { # $1 = rc file
|
|
41
|
+
[ -f "$1" ] || return 0
|
|
42
|
+
awk '
|
|
43
|
+
/^# added by newsline installer$/ {
|
|
44
|
+
marker=$0
|
|
45
|
+
if ((getline pl) > 0) {
|
|
46
|
+
keep=1
|
|
47
|
+
if (match(pl, /\/[^ "]*\/bin/)) {
|
|
48
|
+
d=substr(pl, RSTART, RLENGTH)
|
|
49
|
+
if (system("[ -d \"" d "\" ]") != 0) keep=0
|
|
50
|
+
}
|
|
51
|
+
if (keep) { print marker; print pl }
|
|
52
|
+
next
|
|
53
|
+
}
|
|
54
|
+
print marker; next
|
|
55
|
+
}
|
|
56
|
+
{ print }
|
|
57
|
+
' "$1" > "$1.nltmp" 2>/dev/null && mv "$1.nltmp" "$1"
|
|
58
|
+
}
|
|
59
|
+
for rc in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.profile" "$HOME/.config/fish/config.fish"; do
|
|
60
|
+
prune_stale_newsline_path "$rc"
|
|
61
|
+
done
|
|
62
|
+
|
|
37
63
|
# Register $BIN on PATH for future shells (idempotent), by shell rc file.
|
|
38
64
|
case ":$PATH:" in
|
|
39
65
|
*":$BIN:"*)
|
package/newsline
CHANGED
|
@@ -80,7 +80,8 @@ import json,sys,shlex
|
|
|
80
80
|
env={"lang":"NEWSLINE_LANG","topic":"NEWSLINE_TOPIC","rotate":"NEWSLINE_ROTATE",
|
|
81
81
|
"count":"NEWSLINE_COUNT","maxlen":"NEWSLINE_MAXLEN","icon":"NEWSLINE_ICON",
|
|
82
82
|
"color":"NEWSLINE_COLOR","linkhint":"NEWSLINE_LINKHINT","api":"NEWSLINE_API",
|
|
83
|
-
"endpoint":"NEWSLINE_ENDPOINT","base_statusline":"NEWSLINE_BASE"
|
|
83
|
+
"endpoint":"NEWSLINE_ENDPOINT","base_statusline":"NEWSLINE_BASE",
|
|
84
|
+
"clickhint":"NEWSLINE_CLICKHINT"}
|
|
84
85
|
try: d=json.load(open(sys.argv[1]))
|
|
85
86
|
except Exception: d={}
|
|
86
87
|
for k,name in env.items():
|
|
@@ -154,12 +155,12 @@ cmd_once() {
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
cmd_init() {
|
|
157
|
-
local lang="" topic="" color="" api="" endpoint="" rotate="6" count="15" compose="auto" yes="0" base_override="" a
|
|
158
|
+
local lang="" topic="" color="" api="" endpoint="" rotate="6" count="15" compose="auto" yes="0" base_override="" rotate_set=0 a
|
|
158
159
|
while [ $# -gt 0 ]; do
|
|
159
160
|
case "$1" in
|
|
160
161
|
--lang) lang="$2"; shift 2;; --topic) topic="$2"; shift 2;;
|
|
161
162
|
--api) api="$2"; shift 2;; --endpoint) endpoint="$2"; shift 2;;
|
|
162
|
-
--rotate) rotate="$2"; shift 2;; --count) count="$2"; shift 2;;
|
|
163
|
+
--rotate) rotate="$2"; rotate_set=1; shift 2;; --count) count="$2"; shift 2;;
|
|
163
164
|
--base) base_override="$2"; shift 2;;
|
|
164
165
|
--compose) compose="yes"; shift;; --no-compose) compose="no"; shift;;
|
|
165
166
|
--settings) SETTINGS="$2"; shift 2;; --yes|-y) yes="1"; shift;;
|
|
@@ -181,26 +182,42 @@ cmd_init() {
|
|
|
181
182
|
local avail c; local -a menu=(auto "Auto-detect (now: $(lang_label "$detected"))")
|
|
182
183
|
avail=$(python3 -c "import json,sys;d=json.load(open(sys.argv[1]));print(' '.join(k for k in d if k not in ('default','_comment')))" "$HERE/feeds.json" 2>/dev/null)
|
|
183
184
|
for c in $avail; do menu+=("$c" "$(lang_label "$c")"); done
|
|
184
|
-
echo "
|
|
185
|
+
echo "Newsline language?" >&2
|
|
185
186
|
choose "$detected" "${menu[@]}"; lang="$CHOICE"
|
|
186
187
|
fi
|
|
187
188
|
if [ -z "$topic" ]; then
|
|
188
|
-
echo "
|
|
189
|
+
echo "Newsline topic?" >&2
|
|
189
190
|
choose general \
|
|
190
191
|
general "General" tech "Tech" business "Business" world "World" \
|
|
191
192
|
sports "Sports" science "Science" health "Health" entertainment "Entertainment"
|
|
192
193
|
topic="$CHOICE"
|
|
193
194
|
fi
|
|
194
195
|
local cur_color; cur_color=$(cfg_get color)
|
|
195
|
-
echo "
|
|
196
|
+
echo "Newsline color?" >&2
|
|
196
197
|
choose "${cur_color:-magenta}" \
|
|
197
198
|
default "Terminal default" cyan "Cyan" gray "Gray" white "White" \
|
|
198
199
|
yellow "Yellow" green "Green" blue "Blue" magenta "Magenta" red "Red"
|
|
199
200
|
color="$CHOICE"
|
|
201
|
+
if [ "$rotate_set" = "0" ]; then
|
|
202
|
+
# rotation interval β free-form seconds; blank/invalid keeps the current value
|
|
203
|
+
local cur_rotate; cur_rotate=$(cfg_get rotate); [ -n "$cur_rotate" ] || cur_rotate="$rotate"
|
|
204
|
+
echo "Newsline seconds?" >&2
|
|
205
|
+
printf " # [%s]: " "$cur_rotate" >&2
|
|
206
|
+
local sel_rotate; read -r sel_rotate < "${NL_TTY:-/dev/stdin}"
|
|
207
|
+
case "$sel_rotate" in
|
|
208
|
+
''|*[!0-9]*) rotate="$cur_rotate" ;; # blank or non-numeric -> keep current
|
|
209
|
+
*) rotate="$sel_rotate" ;;
|
|
210
|
+
esac
|
|
211
|
+
[ "$rotate" -ge 1 ] 2>/dev/null || rotate=6
|
|
212
|
+
fi
|
|
200
213
|
else
|
|
201
214
|
# --yes: keep a color previously set via init/`newsline color`; magenta on first run
|
|
202
215
|
lang="${lang:-$detected}"; topic="${topic:-general}"
|
|
203
216
|
color=$(cfg_get color); [ -n "$color" ] || color="magenta"
|
|
217
|
+
# keep an existing rotation interval on re-init unless --rotate was given
|
|
218
|
+
if [ "$rotate_set" = "0" ]; then
|
|
219
|
+
local saved_rotate; saved_rotate=$(cfg_get rotate); [ -n "$saved_rotate" ] && rotate="$saved_rotate"
|
|
220
|
+
fi
|
|
204
221
|
fi
|
|
205
222
|
|
|
206
223
|
# Always KEEP an existing status line and show newsline below it (no prompt).
|
|
@@ -342,6 +359,8 @@ PY
|
|
|
342
359
|
}
|
|
343
360
|
|
|
344
361
|
cmd_uninstall() {
|
|
362
|
+
local purge=0 a
|
|
363
|
+
for a in "$@"; do case "$a" in --purge|-p) purge=1 ;; esac; done
|
|
345
364
|
local base base_obj
|
|
346
365
|
base=$(cfg_get base_statusline)
|
|
347
366
|
base_obj=$(cfg_get_obj base_statusline_obj)
|
|
@@ -378,19 +397,62 @@ PY
|
|
|
378
397
|
local cache="${NEWSLINE_CACHE:-$HOME/.cache/newsline}"
|
|
379
398
|
rm -f "$CONFIG" "$cache/line" "$cache/feeds.resolved.json" "$cache/feeds.resolved.ok" "$cache/notice" 2>/dev/null
|
|
380
399
|
echo "β newsline uninstalled."
|
|
400
|
+
|
|
401
|
+
[ "$purge" = "1" ] || return 0
|
|
402
|
+
# --purge: also remove the CLI binary + the PATH line install.sh added. Only for
|
|
403
|
+
# the install.sh layout ($PREFIX/share/newsline + $PREFIX/bin/newsline); a
|
|
404
|
+
# package-managed install (brew/npm) is left to its own package manager.
|
|
405
|
+
case "$HERE" in
|
|
406
|
+
*/share/newsline)
|
|
407
|
+
local prefix bin rc
|
|
408
|
+
prefix="$(cd "$HERE/../.." 2>/dev/null && pwd)"; bin="$prefix/bin"
|
|
409
|
+
if [ -e "$bin/newsline" ]; then
|
|
410
|
+
rm -f "$bin/newsline"
|
|
411
|
+
rm -rf "$HERE" # $PREFIX/share/newsline (this script's dir)
|
|
412
|
+
for rc in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.profile" "$HOME/.config/fish/config.fish"; do
|
|
413
|
+
[ -f "$rc" ] || continue
|
|
414
|
+
awk -v bin="$bin" '
|
|
415
|
+
function strip(p){ sub(/^\/private/, "", p); return p } # macOS /var == /private/var
|
|
416
|
+
/^# added by newsline installer$/ {
|
|
417
|
+
marker=$0
|
|
418
|
+
if ((getline pl) > 0) {
|
|
419
|
+
drop=0
|
|
420
|
+
if (match(pl, /\/[^ "]*\/bin/)) {
|
|
421
|
+
d=substr(pl, RSTART, RLENGTH)
|
|
422
|
+
if (strip(d) == strip(bin)) drop=1 # our block -> drop marker + path line
|
|
423
|
+
}
|
|
424
|
+
if (drop) next
|
|
425
|
+
print marker; print pl; next
|
|
426
|
+
}
|
|
427
|
+
print marker; next
|
|
428
|
+
}
|
|
429
|
+
{ print }
|
|
430
|
+
' "$rc" > "$rc.nltmp" 2>/dev/null && mv "$rc.nltmp" "$rc"
|
|
431
|
+
done
|
|
432
|
+
echo "β purged CLI: removed $bin/newsline and its PATH entry (open a new shell to refresh PATH)."
|
|
433
|
+
else
|
|
434
|
+
echo "βΉ nothing to purge (no $bin/newsline)."
|
|
435
|
+
fi
|
|
436
|
+
;;
|
|
437
|
+
*)
|
|
438
|
+
echo "βΉ this CLI wasn't installed via install.sh (looks package-managed);"
|
|
439
|
+
echo " remove it with: brew uninstall newsline or npm uninstall -g newsline-cli"
|
|
440
|
+
;;
|
|
441
|
+
esac
|
|
381
442
|
}
|
|
382
443
|
|
|
383
444
|
usage() {
|
|
384
445
|
cat <<'EOF'
|
|
385
446
|
newsline β local news status-line utility
|
|
386
447
|
newsline init [--lang ko] [--topic tech] set up & wire the status line
|
|
387
|
-
|
|
448
|
+
[--rotate SECS] (asks language / topic / color / rotation)
|
|
388
449
|
newsline color [name] set headline color (e.g. cyan, gray); with
|
|
389
450
|
no name, step to the next: default β gray β
|
|
390
451
|
white β cyan β yellow β green β blue β
|
|
391
452
|
magenta β red β back to default
|
|
392
453
|
newsline colorlist list the available colors with a preview
|
|
393
|
-
newsline uninstall
|
|
454
|
+
newsline uninstall [--purge] remove & restore previous status line
|
|
455
|
+
(--purge also deletes the CLI + PATH line)
|
|
394
456
|
EOF
|
|
395
457
|
if [ "${1:-}" = "--all" ]; then
|
|
396
458
|
cat <<'EOF'
|
package/package.json
CHANGED
package/readme/ko.md
CHANGED
|
@@ -68,6 +68,7 @@ npm i -g newsline-cli && newsline init
|
|
|
68
68
|
| `maxlen` | `120` | μ΅λ κΈμμ (`max`=무μ ν) |
|
|
69
69
|
| `icon` | `π°` | μ μμ΄μ½ (`none`μ΄λ©΄ μ κ±°) |
|
|
70
70
|
| `color` | `magenta` | λ΄μ€ κΈμ μ: `default` `gray` `white` `cyan` `yellow` `green` `blue` `magenta` `red` |
|
|
71
|
+
| `clickhint` | `auto` | ν€λλΌμΈ μ ν΄λ¦ μλ΄ (`auto`=ν°λ―Έλλ³ μλ, `off`=μ¨κΉ, λλ μ§μ μ§μ ) |
|
|
71
72
|
|
|
72
73
|
`newsline color <μ΄λ¦>`μΌλ‘ μμ λ°λ‘ μ§μ νκ±°λ(μ: `newsline color gray`), μ΄λ¦ μμ΄
|
|
73
74
|
`newsline color`λ₯Ό μ€ννλ©΄ λ€μ μμΌλ‘ λμ΄κ°λλ€ (default β gray β white β cyan β
|
package/refresh.sh
CHANGED
|
@@ -23,7 +23,7 @@ case "$API" in off|OFF|none|local) API="" ;; esac
|
|
|
23
23
|
COUNT="${NEWSLINE_COUNT:-15}" # how many headlines to cache for rotation
|
|
24
24
|
# Client version, sent to /feed as ?v= for the server-side update nudge.
|
|
25
25
|
# Bump together with package.json when tagging a release.
|
|
26
|
-
export NEWSLINE_VERSION="${NEWSLINE_VERSION:-1.0.
|
|
26
|
+
export NEWSLINE_VERSION="${NEWSLINE_VERSION:-1.0.3}"
|
|
27
27
|
LOCK="$CACHE_DIR/refresh.lock"
|
|
28
28
|
mkdir -p "$CACHE_DIR" 2>/dev/null
|
|
29
29
|
|
package/statusline.sh
CHANGED
|
@@ -42,6 +42,23 @@ colorize() { # wrap text in the configured color (no-op when unset); no newline
|
|
|
42
42
|
if [ -n "$SGR" ]; then printf '\033[%sm%s\033[0m' "$SGR" "$1"; else printf '%s' "$1"; fi
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
# --- per-terminal click hint, printed dim before the headline, e.g. "(Cmd+Click)" ---
|
|
46
|
+
# Headlines are OSC 8 hyperlinks; WHICH modifier opens them is the terminal's call,
|
|
47
|
+
# not ours (macOS terminals use Cmd, most others Ctrl, kitty Ctrl+Shift). Show the
|
|
48
|
+
# right one so users know how to click through. NEWSLINE_CLICKHINT: unset/auto/on =
|
|
49
|
+
# auto-detect; off/none/0 = hide; any other value is used verbatim (e.g. "β-click").
|
|
50
|
+
click_hint() {
|
|
51
|
+
case "$(printf '%s' "${NEWSLINE_CLICKHINT:-}" | tr '[:upper:]' '[:lower:]')" in
|
|
52
|
+
off|none|no|0|false) return 0 ;; # hidden
|
|
53
|
+
''|auto|on|yes|1|true) ;; # auto-detect
|
|
54
|
+
*) printf '\033[90m(%s)\033[0m ' "$NEWSLINE_CLICKHINT"; return 0 ;; # custom label
|
|
55
|
+
esac
|
|
56
|
+
local sys="${OSTYPE:-}"; [ -n "$sys" ] || sys="$(uname -s 2>/dev/null)"
|
|
57
|
+
local mod; case "$sys" in [Dd]arwin*) mod="Cmd+Click" ;; *) mod="Ctrl+Click" ;; esac
|
|
58
|
+
{ [ -n "${KITTY_WINDOW_ID:-}" ] || [ "${TERM:-}" = "xterm-kitty" ]; } && mod="Ctrl+Shift+Click"
|
|
59
|
+
printf '\033[90m(%s)\033[0m ' "$mod"
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
# --- print one headline, rotating across the cached set by wall-clock time ---
|
|
46
63
|
# The cache holds N headlines (one per line). We show a different one every
|
|
47
64
|
# NEWSLINE_ROTATE seconds β a ticker feel with zero stored state.
|
|
@@ -53,6 +70,7 @@ if [ -s "$CACHE_FILE" ]; then
|
|
|
53
70
|
[ "$rot" -ge 1 ] || rot=6 # 0 would divide by zero below
|
|
54
71
|
now="${NEWSLINE_NOW:-$(date +%s)}" # NEWSLINE_NOW overrides clock (tests/debug)
|
|
55
72
|
idx=$(( (now / rot) % n + 1 ))
|
|
73
|
+
click_hint # "(Cmd+Click)" etc., before the linked headline
|
|
56
74
|
colorize "$(sed -n "${idx}p" "$CACHE_FILE")"; printf '\n'
|
|
57
75
|
else
|
|
58
76
|
colorize 'π° β¦'
|