mirror of
https://github.com/daylinmorgan/tsm.git
synced 2024-12-22 05:00:44 -06:00
Compare commits
3 commits
5ca52175f6
...
62ca20fd9b
Author | SHA1 | Date | |
---|---|---|---|
62ca20fd9b | |||
093446e4a6 | |||
97cac40a11 |
8 changed files with 80 additions and 56 deletions
|
@ -3,12 +3,12 @@
|
|||
"packages": {
|
||||
"hwylterm": {
|
||||
"version": "0.1.0",
|
||||
"vcsRevision": "cbeefd675c0884feebad4dc62910092519f8b2ed",
|
||||
"vcsRevision": "f1cc95f86edcc00665fc8280f57edc0e83d461f9",
|
||||
"url": "https://github.com/daylinmorgan/hwylterm",
|
||||
"downloadMethod": "git",
|
||||
"dependencies": [],
|
||||
"checksums": {
|
||||
"sha1": "4d043352ad07388d0181c0fd4cf325317e9306d0"
|
||||
"sha1": "433522bac3b8f3caae252a1a42867ed8dc91f4d2"
|
||||
}
|
||||
},
|
||||
"illwill": {
|
||||
|
|
|
@ -36,11 +36,11 @@
|
|||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1730958623,
|
||||
"narHash": "sha256-JwQZIGSYnRNOgDDoIgqKITrPVil+RMWHsZH1eE1VGN0=",
|
||||
"lastModified": 1731531548,
|
||||
"narHash": "sha256-sz8/v17enkYmfpgeeuyzniGJU0QQBfmAjlemAUYhfy8=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "85f7e662eda4fa3a995556527c87b2524b691933",
|
||||
"rev": "24f0d4acd634792badd6470134c387a3b039dace",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
pname = "tsm";
|
||||
version = "2024.1001-unstable";
|
||||
src = ../.;
|
||||
nimbleDepsHash = "sha256-5xK3KsLLFZ72qWreIHW0SBL3+5H6Ll6o0spMfW1iPX8=";
|
||||
nimbleDepsHash = "sha256-Z+KX1r4tpLQc3hTp2HYI6aLM2cwUCFlWIU8QP/Jx7h4=";
|
||||
nimFlags = [
|
||||
"-d:TsmVersion=v${version}"
|
||||
];
|
||||
|
|
|
@ -9,6 +9,7 @@ type
|
|||
updated*: Time
|
||||
open*: bool
|
||||
matched*: bool
|
||||
tmuxinfo*: string
|
||||
|
||||
proc pathToName*(path: string): string =
|
||||
splitPath(path)[1].replace(".", "_")
|
||||
|
@ -16,10 +17,8 @@ proc pathToName*(path: string): string =
|
|||
proc newProject*(path: string, open: bool, name = "", named: bool = false): Project =
|
||||
result.location = path
|
||||
result.name =
|
||||
if name != "":
|
||||
name
|
||||
else:
|
||||
pathToName(path)
|
||||
if name != "": name
|
||||
else: pathToName(path)
|
||||
result.updated = getLastModificationTime(path)
|
||||
result.open = open
|
||||
result.named = named
|
||||
|
@ -65,10 +64,18 @@ proc `<-`(candidates: var Table[string, seq[string]], path: string) =
|
|||
if candidates.hasKeyOrPut(name, @[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] =
|
||||
let tsmConfig = loadTsmConfig()
|
||||
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 (kind, path) in walkDir(devDir):
|
||||
|
@ -109,7 +116,8 @@ proc findProjects*(open: bool = false): seq[Project] =
|
|||
else: cmp(y.updated, x.updated)
|
||||
|
||||
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:
|
||||
termError "nothing to select, check your [yellow]$TSM_PATHS"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import std/[enumerate, os, strformat, strutils, terminal]
|
||||
import hwylterm
|
||||
from illwill import illwillDeinit, illwillInit, getKey, Key
|
||||
import term, project
|
||||
|
||||
|
@ -34,9 +35,40 @@ type
|
|||
cursor: Cursor
|
||||
projectIdx: Natural
|
||||
projects: seq[Project]
|
||||
selected: seq[Natural]
|
||||
|
||||
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) =
|
||||
b.buffer.add (" " & text).alignLeft(b.width) & "\n"
|
||||
|
||||
|
@ -54,14 +86,6 @@ proc addInput(b: var Buffer) =
|
|||
func numLines(b: Buffer): int =
|
||||
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) =
|
||||
while b.numLines < b.height:
|
||||
b.addLine ""
|
||||
|
@ -130,26 +154,6 @@ proc getProject(): Project =
|
|||
var idx = state.cursor.y - state.cursor.min + state.projectIdx
|
||||
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) =
|
||||
let
|
||||
|
@ -162,15 +166,16 @@ proc addInfoLine(b: var Buffer) =
|
|||
|
||||
proc addProjects(b: var Buffer) =
|
||||
let
|
||||
projects = sortProjects()
|
||||
maxNumProjects = state.buffer.height - state.buffer.inputPad
|
||||
# NOTE: is a bounds error possible?
|
||||
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[state.projectIdx..^1]):
|
||||
b.addProject(project, state.cursor.y == numProjects)
|
||||
inc numProjects
|
||||
if numProjects > maxNumProjects:
|
||||
break
|
||||
for (i, project) in enumerate(projects):
|
||||
let cursorArrow =
|
||||
if state.cursor.y == i + 1: "> "
|
||||
else: " "
|
||||
b.addLine(cursorArrow & $display(state, project))
|
||||
|
||||
proc reset() =
|
||||
state.cursor.y = state.cursor.min
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import std/[os, osproc, strformat, strutils]
|
||||
import std/[os, osproc, strformat, strutils, sequtils]
|
||||
|
||||
import term
|
||||
|
||||
type
|
||||
Tmux = object
|
||||
active: bool
|
||||
sessions*: seq[string]
|
||||
|
||||
TmuxSession* = object
|
||||
name*: string
|
||||
info*: string
|
||||
Tmux* = object
|
||||
active*: bool
|
||||
sessions*: seq[TmuxSession]
|
||||
|
||||
proc checkExe(names: varargs[string]) =
|
||||
for name in names:
|
||||
if findExe(name) == "":
|
||||
|
@ -33,11 +36,18 @@ template cmd(tmux: Tmux, args: string) =
|
|||
tmuxError(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 =
|
||||
result.active = existsEnv("TMUX")
|
||||
# check if server is active
|
||||
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) =
|
||||
let args = if t.active: "switch-client -t" else: "attach -t"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import std/sequtils
|
||||
import ./[selector, project, tmuxutils]
|
||||
import hwylterm, hwylterm/hwylcli
|
||||
|
||||
|
@ -7,7 +8,7 @@ proc tsm(open: bool = false) =
|
|||
project = selectProject projects
|
||||
selected = project.name
|
||||
|
||||
if selected notin tmux.sessions:
|
||||
if selected notin tmux.sessions.mapIt(it.name):
|
||||
tmux.new(project.name, project.location)
|
||||
else:
|
||||
tmux.attach project.name
|
||||
|
|
|
@ -12,6 +12,6 @@ binDir = "bin"
|
|||
|
||||
requires "nim >= 2.0.0"
|
||||
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"
|
||||
|
||||
|
|
Loading…
Reference in a new issue