mirror of
https://github.com/chenasraf/dotfiles.git
synced 2026-05-18 01:29:06 +00:00
feat(tx): project dir loader
chore: cleanups
This commit is contained in:
@@ -137,3 +137,4 @@ alias hli="hl && hi"
|
||||
alias keypresses="xxd -psd"
|
||||
alias install-utils="pushd \$DOTFILES/utils; pnpm install && pnpm build && pnpm ginst; popd"
|
||||
alias lg="lazygit"
|
||||
alias txp="tx p"
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/node": "^20.11.16",
|
||||
"@types/node": "^20.11.17",
|
||||
"cosmiconfig": "^9.0.0",
|
||||
"massarg": "2.0.0",
|
||||
"prettier": "^3.2.4",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
|
||||
22
utils/pnpm-lock.yaml
generated
22
utils/pnpm-lock.yaml
generated
@@ -6,8 +6,8 @@ settings:
|
||||
|
||||
dependencies:
|
||||
'@types/node':
|
||||
specifier: ^20.11.16
|
||||
version: 20.11.16
|
||||
specifier: ^20.11.17
|
||||
version: 20.11.17
|
||||
cosmiconfig:
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0(typescript@5.3.3)
|
||||
@@ -15,11 +15,11 @@ dependencies:
|
||||
specifier: 2.0.0
|
||||
version: 2.0.0
|
||||
prettier:
|
||||
specifier: ^3.2.4
|
||||
version: 3.2.4
|
||||
specifier: ^3.2.5
|
||||
version: 3.2.5
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@20.11.16)(typescript@5.3.3)
|
||||
version: 10.9.2(@types/node@20.11.17)(typescript@5.3.3)
|
||||
typescript:
|
||||
specifier: ^5.3.3
|
||||
version: 5.3.3
|
||||
@@ -87,8 +87,8 @@ packages:
|
||||
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
|
||||
dev: false
|
||||
|
||||
/@types/node@20.11.16:
|
||||
resolution: {integrity: sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==}
|
||||
/@types/node@20.11.17:
|
||||
resolution: {integrity: sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==}
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
dev: false
|
||||
@@ -247,8 +247,8 @@ packages:
|
||||
lines-and-columns: 1.2.4
|
||||
dev: false
|
||||
|
||||
/prettier@3.2.4:
|
||||
resolution: {integrity: sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==}
|
||||
/prettier@3.2.5:
|
||||
resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dev: false
|
||||
@@ -265,7 +265,7 @@ packages:
|
||||
has-flag: 3.0.0
|
||||
dev: false
|
||||
|
||||
/ts-node@10.9.2(@types/node@20.11.16)(typescript@5.3.3):
|
||||
/ts-node@10.9.2(@types/node@20.11.17)(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -284,7 +284,7 @@ packages:
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/node': 20.11.16
|
||||
'@types/node': 20.11.17
|
||||
acorn: 8.11.3
|
||||
acorn-walk: 8.3.2
|
||||
arg: 4.1.3
|
||||
|
||||
@@ -9,6 +9,7 @@ import { showCmd } from './show_cmd'
|
||||
import { editCmd } from './edit_cmd'
|
||||
import { rmCmd } from './rm_cmd'
|
||||
import { attachCmd } from './attach_cmd'
|
||||
import { prjCmd } from './prj_cmd'
|
||||
|
||||
// ================================================================================
|
||||
// Commands
|
||||
@@ -57,4 +58,5 @@ mainCmd
|
||||
.command(rmCmd)
|
||||
.command(createCmd)
|
||||
.command(attachCmd)
|
||||
.command(prjCmd)
|
||||
.parse()
|
||||
|
||||
70
utils/src/tmux/prj_cmd.ts
Normal file
70
utils/src/tmux/prj_cmd.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import * as path from 'node:path'
|
||||
import * as os from 'node:os'
|
||||
import * as fs from 'node:fs/promises'
|
||||
import { Opts, log } from '../common'
|
||||
import { MassargCommand } from 'massarg/command'
|
||||
import { fzf, isDirectory, nameFix, parseConfig, pathExists } from './utils'
|
||||
import { createFromConfig } from './command_builder'
|
||||
import { format } from 'massarg/style'
|
||||
|
||||
export type CreateOpts = Opts & {
|
||||
rootDir?: string
|
||||
window?: string[]
|
||||
save?: boolean
|
||||
saveOnly?: boolean
|
||||
local?: boolean
|
||||
}
|
||||
|
||||
export const prjCmd = new MassargCommand<CreateOpts>({
|
||||
name: 'prj',
|
||||
aliases: ['p'],
|
||||
description: 'Create a new tmux session (temporary) from project folder',
|
||||
run: async (opts) => {
|
||||
try {
|
||||
const devProjects = await getProjects(opts)
|
||||
const output = await fzf(opts, devProjects, { allowCustom: true })
|
||||
if (!output) {
|
||||
throw new Error('No selection')
|
||||
}
|
||||
const projectDir = path.join(os.homedir(), 'Dev', output)
|
||||
const exists = await pathExists(projectDir)
|
||||
if (!exists) {
|
||||
log(opts, `Creating dir: ${projectDir}`)
|
||||
await fs.mkdir(projectDir, { recursive: true })
|
||||
}
|
||||
const config = parseConfig(output, {
|
||||
name: nameFix(output),
|
||||
root: projectDir,
|
||||
windows: ['.'],
|
||||
})
|
||||
return createFromConfig(opts, config)
|
||||
} catch (error) {
|
||||
console.log(format(error?.toString() ?? 'Unknown error', { color: 'red' }))
|
||||
}
|
||||
},
|
||||
})
|
||||
.flag({
|
||||
name: 'verbose',
|
||||
aliases: ['v'],
|
||||
description: 'Verbose logs',
|
||||
})
|
||||
.flag({
|
||||
name: 'dry',
|
||||
aliases: ['d'],
|
||||
description: 'Dry run',
|
||||
})
|
||||
.help({ bindOption: true, bindCommand: true })
|
||||
|
||||
async function getProjects(_opts: Opts) {
|
||||
const devDir = path.join(os.homedir(), 'Dev')
|
||||
|
||||
const devFiles = await fs.readdir(devDir)
|
||||
let devProjects = [] as string[]
|
||||
|
||||
for (const file of devFiles) {
|
||||
if (await isDirectory(path.join(devDir, file))) {
|
||||
devProjects.push(file)
|
||||
}
|
||||
}
|
||||
return devProjects
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { CosmiconfigResult, cosmiconfig } from 'cosmiconfig'
|
||||
import * as path from 'node:path'
|
||||
import * as os from 'node:os'
|
||||
import * as fs from 'node:fs/promises'
|
||||
import { Opts, getCommandOutput, runCommand } from '../common'
|
||||
import { spawn } from 'node:child_process'
|
||||
|
||||
@@ -203,21 +204,21 @@ export function throwNoConfigFound() {
|
||||
[
|
||||
'tmux config file not found, searched in:',
|
||||
'\t' +
|
||||
searchDirs
|
||||
.map((x) =>
|
||||
searchPatterns('tmux')
|
||||
.map((y) => path.join(x, y))
|
||||
.join('\n\t'),
|
||||
)
|
||||
.join('\n\t'),
|
||||
searchDirs
|
||||
.map((x) =>
|
||||
searchPatterns('tmux')
|
||||
.map((y) => path.join(x, y))
|
||||
.join('\n\t'),
|
||||
)
|
||||
.join('\n\t'),
|
||||
'\t' +
|
||||
searchDirs
|
||||
.map((x) =>
|
||||
searchPatterns('tmux_local')
|
||||
.map((y) => path.join(x, y))
|
||||
.join('\n\t'),
|
||||
)
|
||||
.join('\n\t'),
|
||||
searchDirs
|
||||
.map((x) =>
|
||||
searchPatterns('tmux_local')
|
||||
.map((y) => path.join(x, y))
|
||||
.join('\n\t'),
|
||||
)
|
||||
.join('\n\t'),
|
||||
// searchInFor('tmux').map(x => path.join(d)).join('\n\t'),
|
||||
// searchInFor('tmux_local').join('\n\t'),
|
||||
].join('\n'),
|
||||
@@ -241,8 +242,20 @@ export async function sessionExists(opts: Opts, sessionName: string): Promise<bo
|
||||
}
|
||||
}
|
||||
|
||||
export async function fzf(_opts: Opts, inputs: string[]): Promise<string> {
|
||||
const fzf = spawn(`echo "${inputs.join('\n')}" | fzf`, {
|
||||
export type FzfOptions = {
|
||||
allowCustom?: boolean
|
||||
}
|
||||
|
||||
export async function fzf(
|
||||
_opts: Opts,
|
||||
inputs: string[],
|
||||
fzfOpts: FzfOptions = {},
|
||||
): Promise<string> {
|
||||
let cmd = `echo "${inputs.join('\n')}" | fzf`
|
||||
if (fzfOpts.allowCustom) {
|
||||
cmd += ' --print-query | tail -1'
|
||||
}
|
||||
const fzf = spawn(cmd, {
|
||||
stdio: ['inherit', 'pipe', 'inherit'],
|
||||
shell: true,
|
||||
})
|
||||
@@ -250,14 +263,20 @@ export async function fzf(_opts: Opts, inputs: string[]): Promise<string> {
|
||||
fzf.stdout.setEncoding('utf-8')
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
fzf.stdout.on('readable', function () {
|
||||
fzf.stdout.on('readable', function() {
|
||||
const value = fzf.stdout.read()
|
||||
|
||||
if (value !== null) {
|
||||
resolve(value.toString().trim())
|
||||
return
|
||||
}
|
||||
reject()
|
||||
reject(new Error('fzf cancelled or encountered an error'))
|
||||
})
|
||||
|
||||
fzf.on('exit', (code) => {
|
||||
if (code === 1) {
|
||||
reject(new Error('fzf cancelled or encountered an error'))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -306,10 +325,28 @@ function parseLayout(layoutInput: TmuxLayoutInput | undefined, root: string): Tm
|
||||
zoom: layout.zoom,
|
||||
split: layout.split
|
||||
? ({
|
||||
direction:
|
||||
typeof layout.split === 'string' ? layout.split : layout.split.direction || 'h',
|
||||
child: parseLayout(layout.split.child, path.resolve(root, layout.cwd)),
|
||||
} as TmuxSplitLayout)
|
||||
direction:
|
||||
typeof layout.split === 'string' ? layout.split : layout.split.direction || 'h',
|
||||
child: parseLayout(layout.split.child, path.resolve(root, layout.cwd)),
|
||||
} as TmuxSplitLayout)
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
export async function pathExists(path: string) {
|
||||
return fs.stat(path).catch(() => false)
|
||||
}
|
||||
|
||||
export async function isDirectory(path: string) {
|
||||
return fs
|
||||
.stat(path)
|
||||
.then((stat) => stat.isDirectory())
|
||||
.catch(() => false)
|
||||
}
|
||||
|
||||
export async function isFile(path: string) {
|
||||
return fs
|
||||
.stat(path)
|
||||
.then((stat) => stat.isFile())
|
||||
.catch(() => false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user