feat: handle duplicates/and term improvements

This commit is contained in:
Daylin Morgan 2023-10-03 13:06:34 -05:00
parent 1d08c01e6e
commit 8673532e2a
Signed by: daylin
GPG key ID: C1E52E7DD81DF79F
4 changed files with 77 additions and 31 deletions

View file

@ -1,7 +1,5 @@
import std/[algorithm, os, sequtils, sets, strutils, tables, times] import std/[algorithm, os, sequtils, sets, strutils, sugar, tables, times]
import tmuxutils, term
import bbansi
import utils
type type
Project* = object Project* = object
@ -13,22 +11,45 @@ type
proc pathToName(path: string): string = splitPath(path)[1].replace(".", "_") proc pathToName(path: string): string = splitPath(path)[1].replace(".", "_")
proc newProject(path: string, open: bool): Project = proc newProject(path: string, open: bool, name = ""): Project =
result.location = path result.location = path
result.name = path.pathToName() result.name =
if name != "": name
else: path.pathToName()
result.updated = getLastModificationTime(path) result.updated = getLastModificationTime(path)
result.open = open result.open = open
proc newUnknownProject(name: string): Project = proc newUnknownProject(name: string): Project =
result.name = name result.name = name
result.open = true
proc getTsmDirs(): seq[string] = proc getTsmDirs(): seq[string] =
let tsmDirs = getEnv("TSM_DIRS") let tsmDirs = getEnv("TSM_DIRS")
if tsmDirs == "": if tsmDirs == "":
bbEcho "[red]Please set [cyan]$TSM_DIRS[/] to a colon-delimited list of paths" termQuit "Please set [yellow]$TSM_DIRS[/] to a colon-delimited list of paths"
quit QuitFailure
result = tsmDirs.split(":") result = tsmDirs.split(":")
proc findDuplicateProjects(paths: seq[string],
sessions: var HashSet[string]): seq[Project] =
var candidates: Table[string, seq[string]]
for p in paths:
candidates[p] = p.split(DirSep)
let maxExtra = min(candidates.values.toSeq.mapIt(it.len))
for i in 2..maxExtra:
let deduplicated = collect:
for path, pathSplit in candidates.pairs:
(name: pathSplit[^i..^1].joinPath, path: path)
if deduplicated.mapIt(it[0]).toHashSet.len == candidates.len:
for (name, path) in deduplicated:
let open = name in sessions
result.add newProject(path, open, name)
if open: sessions.excl name
break
if result.len == 0:
termQuit "failed to deduplicate these paths:" & paths.join(", ")
proc findProjects*(open: bool = false): seq[Project] = proc findProjects*(open: bool = false): seq[Project] =
var candidates: Table[string, seq[string]] var candidates: Table[string, seq[string]]
var sessions = tmux.sessions.toHashSet() var sessions = tmux.sessions.toHashSet()
@ -36,20 +57,19 @@ proc findProjects*(open: bool = false): seq[Project] =
for devDir in getTsmDirs(): for devDir in getTsmDirs():
for path in walkDir(devDir): for path in walkDir(devDir):
if ({path.kind} * {pcFile, pcLinkToFile}).len > 0: continue if ({path.kind} * {pcFile, pcLinkToFile}).len > 0: continue
let name = path.path.tailDir() let name = path.path.splitPath.tail
if name in candidates: if candidates.hasKeyOrPut(name, @[path.path]):
candidates[name].add path.path candidates[name].add path.path
else:
candidates[name] = @[path.path]
# TODO: improve this to handle duplicate entries by appending parent? for name, paths in candidates.pairs:
for name, paths in candidates:
if len(paths) == 1: if len(paths) == 1:
let path = paths[0] let
let open = path.pathToName in sessions path = paths[0]
open = path.pathToName in sessions
result.add newProject(path, open) result.add newProject(path, open)
if open: if open: sessions.excl path.pathToName
sessions.excl toHashSet([path.pathToName]) else:
result &= findDuplicateProjects(paths, sessions)
if open: if open:
result = result.filterIt(it.open) result = result.filterIt(it.open)
@ -64,7 +84,8 @@ proc findProjects*(open: bool = false): seq[Project] =
result = sessions.toSeq().mapIt(newUnknownProject(it)) & result result = sessions.toSeq().mapIt(newUnknownProject(it)) & result
if len(result) == 0: if len(result) == 0:
echo "nothing to select" termError "nothing to select, check your [yellow]$TSM_DIRS"
quit 1 termEcho "searched these directories: "
echo getTsmDirs().mapIt(" " & it).join("\n")
quit QuitFailure

17
src/term.nim Normal file
View file

@ -0,0 +1,17 @@
import std/strutils
import bbansi
const
sep = " [magenta]|[/] "
prefix = "[cyan]tsm[/]" & sep
errPrefix = prefix & "[red]error[/]" & sep
proc termEcho*(x: varargs[string, `$`]) =
bbEcho prefix, x.join(" ")
proc termError*(x: varargs[string, `$`]) =
bbEcho errPrefix, x.join(" ")
proc termQuit*(x: varargs[string, `$`]) =
termError x
quit QuitFailure

View file

@ -1,5 +1,7 @@
import std/[os, osproc, strformat, strutils] import std/[os, osproc, strformat, strutils]
import term
type type
Tmux = object Tmux = object
active: bool active: bool
@ -8,24 +10,31 @@ type
proc checkExe(names: varargs[string]) = proc checkExe(names: varargs[string]) =
for name in names: for name in names:
if findExe(name) == "": if findExe(name) == "":
echo "tsm requires " & name termError "tsm requires " & name
checkExe "tmux" checkExe "tmux"
proc tmuxError(args: string, output: string = "") =
termError "failed to run: [bold]tmux", args
if output != "":
termError "see below for error"
echo output
quit QuitFailure
proc cmdGet(tmux: Tmux, args: string): string = proc cmdGet(tmux: Tmux, args: string): string =
let (output, code) = execCmdEx("tmux " & args) let (output, code) = execCmdEx("tmux " & args)
if code != 0: if code == 0: return output
echo "ERROR: failed to run: tmux ", args, "see below for error" tmuxError args, output
echo output
quit QuitFailure
return output
template cmd(tmux: Tmux, args: string) = template cmd(tmux: Tmux, args: string) =
discard execCmd("tmux " & args) let code = execCmd "tmux " & args
if code != 0: tmuxError(args)
# discard tmux.cmdGet args
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.sessions = (
result.cmdGet "list-sessions -F '#S'" result.cmdGet "list-sessions -F '#S'"
@ -44,5 +53,4 @@ proc new*(t: Tmux, session: string, loc: string) =
else: else:
t.cmd fmt"new-session -s {session} -c {loc}" t.cmd fmt"new-session -s {session} -c {loc}"
let tmux* = newTmux() let tmux* = newTmux()

View file

@ -1,6 +1,6 @@
import std/[tables] import std/[tables]
import selector, project, utils import selector, project, tmuxutils
proc tsm(open: bool = false) = proc tsm(open: bool = false) =
let let