Compare commits

..

3 commits

Author SHA1 Message Date
62ca20fd9b
update nix flake 2024-11-14 17:18:33 -06:00
093446e4a6
nix/flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:nixos/nixpkgs/85f7e662eda4fa3a995556527c87b2524b691933' (2024-11-07)
  → 'github:nixos/nixpkgs/24f0d4acd634792badd6470134c387a3b039dace' (2024-11-13)
2024-11-14 17:17:13 -06:00
97cac40a11
add session info to open sessions 2024-11-14 17:15:13 -06:00
8 changed files with 80 additions and 56 deletions

View file

@ -3,12 +3,12 @@
"packages": { "packages": {
"hwylterm": { "hwylterm": {
"version": "0.1.0", "version": "0.1.0",
"vcsRevision": "cbeefd675c0884feebad4dc62910092519f8b2ed", "vcsRevision": "f1cc95f86edcc00665fc8280f57edc0e83d461f9",
"url": "https://github.com/daylinmorgan/hwylterm", "url": "https://github.com/daylinmorgan/hwylterm",
"downloadMethod": "git", "downloadMethod": "git",
"dependencies": [], "dependencies": [],
"checksums": { "checksums": {
"sha1": "4d043352ad07388d0181c0fd4cf325317e9306d0" "sha1": "433522bac3b8f3caae252a1a42867ed8dc91f4d2"
} }
}, },
"illwill": { "illwill": {

View file

@ -36,11 +36,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1730958623, "lastModified": 1731531548,
"narHash": "sha256-JwQZIGSYnRNOgDDoIgqKITrPVil+RMWHsZH1eE1VGN0=", "narHash": "sha256-sz8/v17enkYmfpgeeuyzniGJU0QQBfmAjlemAUYhfy8=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "85f7e662eda4fa3a995556527c87b2524b691933", "rev": "24f0d4acd634792badd6470134c387a3b039dace",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -43,7 +43,7 @@
pname = "tsm"; pname = "tsm";
version = "2024.1001-unstable"; version = "2024.1001-unstable";
src = ../.; src = ../.;
nimbleDepsHash = "sha256-5xK3KsLLFZ72qWreIHW0SBL3+5H6Ll6o0spMfW1iPX8="; nimbleDepsHash = "sha256-Z+KX1r4tpLQc3hTp2HYI6aLM2cwUCFlWIU8QP/Jx7h4=";
nimFlags = [ nimFlags = [
"-d:TsmVersion=v${version}" "-d:TsmVersion=v${version}"
]; ];

View file

@ -9,6 +9,7 @@ type
updated*: Time updated*: Time
open*: bool open*: bool
matched*: bool matched*: bool
tmuxinfo*: string
proc pathToName*(path: string): string = proc pathToName*(path: string): string =
splitPath(path)[1].replace(".", "_") splitPath(path)[1].replace(".", "_")
@ -16,10 +17,8 @@ proc pathToName*(path: string): string =
proc newProject*(path: string, open: bool, name = "", named: bool = false): Project = proc newProject*(path: string, open: bool, name = "", named: bool = false): Project =
result.location = path result.location = path
result.name = result.name =
if name != "": if name != "": name
name else: pathToName(path)
else:
pathToName(path)
result.updated = getLastModificationTime(path) result.updated = getLastModificationTime(path)
result.open = open result.open = open
result.named = named result.named = named
@ -65,10 +64,18 @@ proc `<-`(candidates: var Table[string, seq[string]], path: string) =
if candidates.hasKeyOrPut(name, @[path]): if candidates.hasKeyOrPut(name, @[path]):
candidates[name].add path candidates[name].add path
func projectFromSession(s: TmuxSession): Project =
result.name = s.name
result.open = true
result.tmuxinfo = s.info
proc findProjects*(open: bool = false): seq[Project] = proc findProjects*(open: bool = false): seq[Project] =
let tsmConfig = loadTsmConfig() let tsmConfig = loadTsmConfig()
var candidates: Table[string, seq[string]] var candidates: Table[string, seq[string]]
var sessions = tmux.sessions.toHashSet() var sessions = tmux.sessions.mapIt(it.name).toHashSet()
for devDir in tsmConfig.paths: for devDir in tsmConfig.paths:
for (kind, path) in walkDir(devDir): for (kind, path) in walkDir(devDir):
@ -109,7 +116,8 @@ proc findProjects*(open: bool = false): seq[Project] =
else: cmp(y.updated, x.updated) else: cmp(y.updated, x.updated)
if sessions.len > 0: if sessions.len > 0:
result = sessions.toSeq().mapIt(newUnknownProject(it)) & result result = tmux.sessions.filterIt(it.name in sessions).mapIt(projectFromSession(it)) & result
# result = sessions.toSeq().mapIt(newUnknownProject(it)) & result
if len(result) == 0: if len(result) == 0:
termError "nothing to select, check your [yellow]$TSM_PATHS" termError "nothing to select, check your [yellow]$TSM_PATHS"

View file

@ -1,4 +1,5 @@
import std/[enumerate, os, strformat, strutils, terminal] import std/[enumerate, os, strformat, strutils, terminal]
import hwylterm
from illwill import illwillDeinit, illwillInit, getKey, Key from illwill import illwillDeinit, illwillInit, getKey, Key
import term, project import term, project
@ -34,9 +35,40 @@ type
cursor: Cursor cursor: Cursor
projectIdx: Natural projectIdx: Natural
projects: seq[Project] projects: seq[Project]
selected: seq[Natural]
var state = State() var state = State()
func clip(
s: string,
width: int = state.buffer.width - 3
): string =
result =
if s.len > width: s[0..width]
else: s
func highlight(p: Project): string =
if p.location == "": "green"
elif p.open: "bold yellow"
elif p.named: "cyan"
else: "default"
proc display(s: State, p: Project): Bbstring =
let
name = p.name.clip
input = s.input.clip
if p.matched:
result.add input.bb("red")
if input.len < name.len:
result.add ($name[input.len..^1]).bb(p.highlight)
else:
result.add name.bb(p.highlight)
if p.tmuxinfo != "":
# will fail without clip!
result.add p.tmuxinfo.bb("faint")
func addLine(b: var Buffer, text: string) = func addLine(b: var Buffer, text: string) =
b.buffer.add (" " & text).alignLeft(b.width) & "\n" b.buffer.add (" " & text).alignLeft(b.width) & "\n"
@ -54,14 +86,6 @@ proc addInput(b: var Buffer) =
func numLines(b: Buffer): int = func numLines(b: Buffer): int =
b.buffer.count '\n' b.buffer.count '\n'
func clip(
s: string,
width: int = state.buffer.width - 3
): string =
result =
if s.len > width: s[0..width]
else: s
proc draw(b: var Buffer) = proc draw(b: var Buffer) =
while b.numLines < b.height: while b.numLines < b.height:
b.addLine "" b.addLine ""
@ -130,26 +154,6 @@ proc getProject(): Project =
var idx = state.cursor.y - state.cursor.min + state.projectIdx var idx = state.cursor.y - state.cursor.min + state.projectIdx
return projects[idx] return projects[idx]
func highlight(p: Project): string =
if p.location == "": "green"
elif p.open: "bold yellow"
elif p.named: "cyan"
else: "default"
proc addProject(b: var Buffer, project: Project, selected: bool) =
let
name = project.name.clip
input = state.input.clip
cur = (if selected: "> " else: " ")
if project.matched:
var displayName = fmt"[red]{input}[/]"
if input.len < name.len:
displayName &=
fmt"[{project.highlight}]{name[input.len..^1]}[/{project.highlight}]"
b.addLine(cur & $displayName.bb)
else:
b.addLine(cur & $name.bb(project.highlight))
proc addInfoLine(b: var Buffer) = proc addInfoLine(b: var Buffer) =
let let
@ -162,15 +166,16 @@ proc addInfoLine(b: var Buffer) =
proc addProjects(b: var Buffer) = proc addProjects(b: var Buffer) =
let let
projects = sortProjects() # NOTE: is a bounds error possible?
maxNumProjects = state.buffer.height - state.buffer.inputPad nProjects = min(state.buffer.height - state.buffer.inputPad, state.projects.len() - state.projectIdx)
slice = state.projectIdx..<(state.projectIdx + nProjects)
projects = sortProjects()[slice]
var numProjects = 1 for (i, project) in enumerate(projects):
for (i, project) in enumerate(projects[state.projectIdx..^1]): let cursorArrow =
b.addProject(project, state.cursor.y == numProjects) if state.cursor.y == i + 1: "> "
inc numProjects else: " "
if numProjects > maxNumProjects: b.addLine(cursorArrow & $display(state, project))
break
proc reset() = proc reset() =
state.cursor.y = state.cursor.min state.cursor.y = state.cursor.min

View file

@ -1,11 +1,14 @@
import std/[os, osproc, strformat, strutils] import std/[os, osproc, strformat, strutils, sequtils]
import term import term
type type
Tmux = object TmuxSession* = object
active: bool name*: string
sessions*: seq[string] info*: string
Tmux* = object
active*: bool
sessions*: seq[TmuxSession]
proc checkExe(names: varargs[string]) = proc checkExe(names: varargs[string]) =
for name in names: for name in names:
@ -33,11 +36,18 @@ template cmd(tmux: Tmux, args: string) =
tmuxError(args) tmuxError(args)
# discard tmux.cmdGet args # discard tmux.cmdGet args
proc toSession(s: string): TmuxSession =
let ss = s.split(":", 1)
if ss.len != 2:
tmuxError "failed to parse session info from: " & s
result.name = ss[0]
result.info = ss[1]
proc newTmux(): Tmux = proc newTmux(): Tmux =
result.active = existsEnv("TMUX") result.active = existsEnv("TMUX")
# check if server is active # check if server is active
if execCmdEx("tmux run").exitCode == 0: if execCmdEx("tmux run").exitCode == 0:
result.sessions = (result.cmdGet "list-sessions -F '#S'").strip().split("\n") result.sessions = (result.cmdGet "list-sessions").strip().split("\n").mapIt(toSession(it))
proc attach*(t: Tmux, session: string) = proc attach*(t: Tmux, session: string) =
let args = if t.active: "switch-client -t" else: "attach -t" let args = if t.active: "switch-client -t" else: "attach -t"

View file

@ -1,3 +1,4 @@
import std/sequtils
import ./[selector, project, tmuxutils] import ./[selector, project, tmuxutils]
import hwylterm, hwylterm/hwylcli import hwylterm, hwylterm/hwylcli
@ -7,7 +8,7 @@ proc tsm(open: bool = false) =
project = selectProject projects project = selectProject projects
selected = project.name selected = project.name
if selected notin tmux.sessions: if selected notin tmux.sessions.mapIt(it.name):
tmux.new(project.name, project.location) tmux.new(project.name, project.location)
else: else:
tmux.attach project.name tmux.attach project.name

View file

@ -12,6 +12,6 @@ binDir = "bin"
requires "nim >= 2.0.0" requires "nim >= 2.0.0"
requires "illwill >= 0.4.1" requires "illwill >= 0.4.1"
requires "https://github.com/daylinmorgan/hwylterm#cbeefd67" requires "https://github.com/daylinmorgan/hwylterm#f1cc95f8"
requires "https://github.com/usu-dev/usu-nim" requires "https://github.com/usu-dev/usu-nim"