Files
herolib/lib/osal/tmux/tmux_window.v
2025-07-21 06:18:46 +02:00

258 lines
6.8 KiB
V

module tmux
import os
import freeflowuniverse.herolib.osal.core as osal
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.data.ourtime
import time
import freeflowuniverse.herolib.ui.console
@[heap]
struct Window {
pub mut:
session &Session @[skip]
name string
id int
active bool
pid int
paneid int
cmd string
env map[string]string
}
pub struct WindowArgs {
pub mut:
name string
cmd string
env map[string]string
reset bool
}
// window_name is the name of the window in session main (will always be called session main)
// cmd to execute e.g. bash file
// environment arguments to use
// reset, if reset it will create window even if it does already exist, will destroy it
// ```
// struct WindowArgs {
// pub mut:
// name string
// cmd string
// env map[string]string
// reset bool
// }
// ```
pub fn (mut t Tmux) window_new(args WindowArgs) !Window {
mut s := t.session_create(name: 'main', reset: false)!
mut w := s.window_new(args)!
return w
}
// is always in the main tmux
pub fn (mut t Tmux) window_delete(args WindowGetArgs) ! {
mut s := t.session_create(name: 'main', reset: false)!
s.window_delete(name: args.name)!
}
// window_name is the name of the window in session main (will always be called session main)
// cmd to execute e.g. bash file
// environment arguments to use
// reset, if reset it will create window even if it does already exist, will destroy it
// ```
// struct WindowArgs {
// pub mut:
// name string
// cmd string
// env map[string]string
// reset bool
// }
// ```
pub fn (mut s Session) window_new(args WindowArgs) !Window {
$if debug {
console.print_header(' start window: \n${args}')
}
namel := texttools.name_fix(args.name)
if s.window_exist(name: namel) {
if args.reset {
s.window_delete(name: namel)!
} else {
return error('cannot create new window it already exists, window ${namel} in session:${s.name}')
}
}
mut w := Window{
session: &s
name: namel
cmd: args.cmd
env: args.env
}
s.windows << &w
w.create()!
s.window_delete(name: 'notused')!
return w
}
pub struct WindowGetArgs {
pub mut:
name string
cmd string
id int
}
fn (mut s Session) window_exist(args_ WindowGetArgs) bool {
mut args := args_
s.window_get(args) or { return false }
return true
}
pub fn (mut s Session) window_get(args_ WindowGetArgs) !&Window {
mut args := args_
args.name = texttools.name_fix(args.name)
for w in s.windows {
if w.name == args.name {
if (args.id > 0 && w.id == args.id) || args.id == 0 {
return w
}
}
}
return error('Cannot find window ${args.name} in session:${s.name}')
}
pub fn (mut s Session) window_delete(args_ WindowGetArgs) ! {
// $if debug { console.print_debug(" - window delete: $args_")}
mut args := args_
args.name = texttools.name_fix(args.name)
if !(s.window_exist(args)) {
return
}
mut i := 0
for mut w in s.windows {
if w.name == args.name {
if (args.id > 0 && w.id == args.id) || args.id == 0 {
w.stop()!
break
}
}
i += 1
}
s.windows.delete(i) // i is now the one in the list which needs to be removed
}
pub fn (mut w Window) create() ! {
// tmux new-window -P -c /tmp -e good=1 -e bad=0 -n koekoe -t main bash
if w.cmd.contains('\n') {
// means is multiline need to write it
// scriptpath string // is the path where the script will be put which is executed
// scriptkeep bool // means we don't remove the script
os.mkdir_all('/tmp/tmux/${w.session.name}')!
cmd_new := osal.exec_string(
cmd: w.cmd
scriptpath: '/tmp/tmux/${w.session.name}/${w.name}.sh'
scriptkeep: true
)!
w.cmd = cmd_new
}
// console.print_debug(w)
if w.active == false {
res_opt := "-P -F '#{session_name}|#{window_name}|#{window_id}|#{pane_active}|#{pane_id}|#{pane_pid}|#{pane_start_command}'"
cmd := 'tmux new-window ${res_opt} -t ${w.session.name} -n ${w.name} \'/bin/bash -c ${w.cmd}\''
console.print_debug(cmd)
res := osal.exec(cmd: cmd, stdout: false, name: 'tmux_window_create') or {
return error("Can't create new window ${w.name} \n${cmd}\n${err}")
}
// now look at output to get the window id = wid
line_arr := res.output.split('|')
wid := line_arr[2] or { panic('cannot split line for window create.\n${line_arr}') }
w.id = wid.replace('@', '').int()
$if debug {
console.print_header(' WINDOW - Window: ${w.name} created in session: ${w.session.name}')
}
} else {
return error('cannot create window, it already exists.\n${w.name}:${w.id}:${w.cmd}')
}
}
// do some good checks if the window is still active
// not implemented yet
pub fn (mut w Window) check() ! {
panic('not implemented yet')
}
// restart the window
pub fn (mut w Window) restart() ! {
w.stop()!
w.create()!
}
// stop the window
pub fn (mut w Window) stop() ! {
osal.exec(
cmd: 'tmux kill-window -t @${w.id}'
stdout: false
name: 'tmux_kill-window'
// die: false
) or { return error("Can't kill window with id:${w.id}: ${err}") }
w.pid = 0
w.active = false
}
pub fn (window Window) str() string {
return ' - name:${window.name} wid:${window.id} active:${window.active} pid:${window.pid} cmd:${window.cmd}'
}
// will select the current window so with tmux a we can go there .
// to login into a session do `tmux a -s mysessionname`
fn (mut w Window) activate() ! {
cmd2 := 'tmux select-window -t %${w.id}'
osal.execute_silent(cmd2) or {
return error("Couldn't select window ${w.name} \n${cmd2}\n${err}")
}
}
// show the environment
pub fn (mut w Window) environment_print() ! {
res := osal.execute_silent('tmux show-environment -t %${w.paneid}') or {
return error('Couldnt show enviroment cmd: ${w.cmd} \n${err}')
}
os.log(res)
}
// capture the output
pub fn (mut w Window) output_print() ! {
o := w.output()!
console.print_debug(o)
}
// capture the output
pub fn (mut w Window) output() !string {
//-S is start, minus means go in history, otherwise its only the active output
// tmux capture-pane -t your-session-name:your-window-number -S -1000
cmd := 'tmux capture-pane -t ${w.session.name}:@${w.id} -S -1000 && tmux show-buffer'
res := osal.execute_silent(cmd) or {
return error('Couldnt show enviroment cmd: ${w.cmd} \n${err}')
}
return texttools.remove_empty_lines(res)
}
pub fn (mut w Window) output_wait(c_ string, timeoutsec int) ! {
mut t := ourtime.now()
start := t.unix()
c := c_.replace('\n', '')
for i in 0 .. 2000 {
o := w.output()!
// console.print_debug(o)
$if debug {
console.print_debug(" - tmux ${w.name}: wait for: '${c}'")
}
// need to replace \n because can be wrapped because of size of pane
if o.replace('\n', '').contains(c) {
return
}
mut t2 := ourtime.now()
if t2.unix() > start + timeoutsec {
return error('timeout on output wait for tmux.\n${w} .\nwaiting for:\n${c}')
}
time.sleep(100 * time.millisecond)
}
}