Skip to content

Commit 01bfa79

Browse files
committed
feat: ✨ support tmux
1 parent 4b781f0 commit 01bfa79

File tree

6 files changed

+103
-20
lines changed

6 files changed

+103
-20
lines changed

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,18 @@ codezm.workflows.fcs-python
1313

1414
## 使用
1515

16-
[点击下载 alfredworkflow](https://github.com/codezm/codezm.workflows.fcs-python/releases/download/v1.0.0/codezm.workflows.fcs-python.alfredworkflow)
16+
[点击下载 alfredworkflow](https://github.com/codezm/codezm.workflows.fcs-python/releases/download/v1.0.1/codezm.workflows.fcs-python.alfredworkflow)
17+
18+
## 环境变量
19+
- PYTHON_PATH: python 可执行脚本路径。
20+
- REDIS_DATA_FILE_PATH: redis 数据存储路径。
21+
- SSH_DATA_FILE_PATH: ssh 数据存储路径。
22+
- TMUX_SESSION_NAME: tmux 会话名称。值不为空时,新的 ssh 连接会加入到 tmux 指定会话中。
23+
- 如果 TMUX_SESSION_NAME 不存在,则会自动创建。
24+
- 默认将使用自定义服务器名作为 tmux window 命名。
25+
- 如果 iTerm 页签没有找到 TMUX_SESSION_NAME,则会自动通过 tmux attach -t TMUX_SESSION_NAME 进入会话,否则将通过 tmux send-keys 创建新的 window 并切换至 iTerm 中标签页名为 TMUX_SESSION_NAME 的页签。
26+
- 如果将创建的 window 名已经存在,则将创建新的 iTerm Tab。
27+
- separator: 分隔符。用于列表展示时标题名称分隔符。
1728

1829
### ssh
1930

1.2 KB
Binary file not shown.

info.plist

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<dict>
55
<key>bundleid</key>
66
<string>codezm.workflows.fcs-python</string>
7+
<key>category</key>
8+
<string>Tools</string>
79
<key>connections</key>
810
<dict>
911
<key>04DC4EC1-9B7E-469E-8C95-5CE7D8840B85</key>
@@ -758,7 +760,7 @@
758760
<key>hotkey</key>
759761
<integer>18</integer>
760762
<key>hotmod</key>
761-
<integer>262144</integer>
763+
<integer>524288</integer>
762764
<key>hotstring</key>
763765
<string>1</string>
764766
<key>leftcursor</key>
@@ -795,7 +797,7 @@
795797
<key>hotkey</key>
796798
<integer>19</integer>
797799
<key>hotmod</key>
798-
<integer>262144</integer>
800+
<integer>524288</integer>
799801
<key>hotstring</key>
800802
<string>2</string>
801803
<key>leftcursor</key>
@@ -832,7 +834,7 @@
832834
<key>hotkey</key>
833835
<integer>20</integer>
834836
<key>hotmod</key>
835-
<integer>262144</integer>
837+
<integer>524288</integer>
836838
<key>hotstring</key>
837839
<string>3</string>
838840
<key>leftcursor</key>
@@ -870,7 +872,17 @@
870872
871873
## 使用
872874
873-
[点击下载 alfredworkflow](https://github.com/codezm/codezm.workflows.fcs-python/releases/download/v1.0.0/codezm.workflows.fcs-python.alfredworkflow)
875+
[点击下载 alfredworkflow](https://github.com/codezm/codezm.workflows.fcs-python/releases/download/v1.0.1/codezm.workflows.fcs-python.alfredworkflow)
876+
## 环境变量介绍
877+
- PYTHON_PATH: python 可执行脚本路径。
878+
- REDIS_DATA_FILE_PATH: redis 数据存储路径。
879+
- SSH_DATA_FILE_PATH: ssh 数据存储路径。
880+
- TMUX_SESSION_NAME: tmux 会话名称。值不为空时,新的 ssh 连接会加入到 tmux 指定会话中。
881+
- 如果 TMUX_SESSION_NAME 不存在,则会自动创建。
882+
- 默认将使用自定义服务器名作为 tmux window 命名。
883+
- 如果 iTerm 页签没有找到 TMUX_SESSION_NAME,则会自动通过 tmux attach -t TMUX_SESSION_NAME 进入会话,否则将通过 tmux send-keys 创建新的 window 并切换至 iTerm 中标签页名为 TMUX_SESSION_NAME 的页签。
884+
- 如果将创建的 window 名已经存在,则将创建新的 iTerm Tab。
885+
- separator: 分隔符。用于列表展示时标题名称分隔符。
874886
875887
### ssh
876888
@@ -1127,18 +1139,23 @@
11271139
<key>variables</key>
11281140
<dict>
11291141
<key>PYTHON_PATH</key>
1130-
<string>/usr/local/bin/python3</string>
1131-
<key>REDIS_DATA_FILE_NAME</key>
1142+
<string>/usr/bin/python3</string>
1143+
<key>REDIS_DATA_FILE_PATH</key>
11321144
<string>data/redis-data.json</string>
1133-
<key>SSH_DATA_FILE_NAME</key>
1145+
<key>SSH_DATA_FILE_PATH</key>
11341146
<string>data/ssh-data.json</string>
1147+
<key>TMUX_SESSION_NAME</key>
1148+
<string>remote-server</string>
11351149
<key>separator</key>
11361150
<string> | </string>
11371151
</dict>
11381152
<key>variablesdontexport</key>
1139-
<array/>
1153+
<array>
1154+
<string>REDIS_DATA_FILE_PATH</string>
1155+
<string>SSH_DATA_FILE_PATH</string>
1156+
</array>
11401157
<key>version</key>
1141-
<string>1.0.0</string>
1158+
<string>1.0.1</string>
11421159
<key>webaddress</key>
11431160
<string>https://github.com/codezm/codezm.workflows.fcs-python</string>
11441161
</dict>

redis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# 环境变量
88
separator = os.environ.get("separator", " | ")
9-
dataFileName = os.environ.get("REDIS_DATA_FILE_NAME", "data/redis-data.json")
9+
dataFileName = os.environ.get("REDIS_DATA_FILE_PATH", "data/redis-data.json")
1010

1111
class Server(BaseServer):
1212
data = []

scp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# 环境变量
88
separator = os.environ.get("separator", " | ")
9-
dataFileName = os.environ.get("SSH_DATA_FILE_NAME", "data/ssh-data.json")
9+
dataFileName = os.environ.get("SSH_DATA_FILE_PATH", "data/ssh-data.json")
1010

1111
class Server(BaseServer):
1212
data = []

ssh.py

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import sys
44
import os
55
from BaseServer import BaseServer
6+
import subprocess
67

78
# 环境变量
9+
os.environ["PATH"] = "/usr/local/bin:/opt/homebrew/bin:" + os.environ.get("PATH", "")
810
separator = os.environ.get("separator", " | ")
9-
sshDataFileName = os.environ.get("SSH_DATA_FILE_NAME", "data/ssh-data.json")
11+
sshDataFileName = os.environ.get("SSH_DATA_FILE_PATH", "data/ssh-data.json")
12+
TMUX_SESSION_NAME = os.environ.get("TMUX_SESSION_NAME", "")
1013

1114
class sshServer(BaseServer):
1215
data = []
@@ -25,11 +28,63 @@ def __init__(self, serverDataFile):
2528
f"/usr/bin/expect {self.workFlowPath}/login.expect",
2629
]
2730

31+
def has_tab_with_session_name(self, name_fragment):
32+
"""检查是否有标签页的会话名称包含指定字符串"""
33+
34+
applescript = f'''
35+
tell application "iTerm"
36+
if (count of windows) = 0 then
37+
return false
38+
end if
39+
40+
repeat with w in windows
41+
tell w
42+
repeat with aTab in tabs
43+
try
44+
if (name of current session of aTab) contains "{name_fragment}" then
45+
return true
46+
end if
47+
on error
48+
-- 忽略错误
49+
end try
50+
end repeat
51+
end tell
52+
end repeat
53+
54+
return false
55+
end tell
56+
'''
57+
58+
try:
59+
result = subprocess.run(['osascript', '-e', applescript],
60+
capture_output=True, text=True, timeout=5)
61+
output = result.stdout.strip().lower()
62+
return output == "true"
63+
except Exception as e:
64+
return False
65+
2866
def run(self, methodName, *args, **kwargs):
2967
method = getattr(self, methodName, None)
3068
if method and callable(method):
31-
result = method(*args, **kwargs)
32-
print(result, end='')
69+
name, result = method(*args, **kwargs)
70+
if TMUX_SESSION_NAME and (methodName == "getByIndex" or methodName == "add"):
71+
name = name.replace(".", "_")
72+
# check tmux session exist
73+
session_check = subprocess.run(["tmux", "has-session", "-t", TMUX_SESSION_NAME], capture_output=True)
74+
if session_check.returncode != 0:
75+
# create tmux session
76+
subprocess.run(["tmux", "new-session", "-d", "-s", TMUX_SESSION_NAME])
77+
# check tmux window exist
78+
window_check = subprocess.run(["tmux", "list-windows", "-t", TMUX_SESSION_NAME, "-F", "#{window_name}"], capture_output=True, text=True)
79+
if name not in window_check.stdout.splitlines():
80+
if self.has_tab_with_session_name(TMUX_SESSION_NAME):
81+
print(f"tmux new-window -t {TMUX_SESSION_NAME} -n \"{name}\" && tmux send-keys -t {TMUX_SESSION_NAME}:{name} \"{result}\" Enter && osascript -e 'tell application \"iTerm\" to tell current window to tell current tab to close' && osascript -e 'tell application \"iTerm\"' -e 'tell current window' -e 'repeat with aTab in tabs' -e 'tell aTab' -e 'if (name of current session) contains \"{TMUX_SESSION_NAME}\" then' -e 'select aTab' -e 'exit repeat' -e 'end if' -e 'end tell' -e 'end repeat' -e 'end tell' -e 'end tell'", end='')
82+
else:
83+
print(f"tmux new-window -t {TMUX_SESSION_NAME} -n \"{name}\" && tmux send-keys -t {TMUX_SESSION_NAME}:{name} \"{result}\" Enter && tmux attach -t {TMUX_SESSION_NAME}", end='')
84+
else:
85+
print(result, end='')
86+
else:
87+
print(result, end='')
3388
else:
3489
raise AttributeError(f"Method {methodName} not found")
3590

@@ -55,7 +110,7 @@ def delete(self, keywordIndex):
55110
if 'rootpwd' in item:
56111
output.append(item['rootpwd'])
57112

58-
return "\n".join(output)
113+
return "", "\n".join(output)
59114
except IndexError:
60115
return 'Delete Failed! Server may be remove!'
61116

@@ -74,7 +129,7 @@ def copy(self, keywordIndex):
74129
if 'rootpwd' in item:
75130
output.append(item['rootpwd'])
76131

77-
return "\n".join(output)
132+
return "", "\n".join(output)
78133
except IndexError:
79134
return 'Copy Failed! Server may be remove!'
80135

@@ -131,7 +186,7 @@ def add(self, info, addLabel="add"):
131186
else:
132187
self.args.append(f"'{item['host']}'")
133188

134-
return " ".join(self.args)
189+
return item['name'], " ".join(self.args)
135190

136191
def get(self, keyword):
137192
queryList = []
@@ -168,7 +223,7 @@ def get(self, keyword):
168223
item['title'] = 'Input <enter> to save.'
169224
item['valid'] = True
170225
queryList.append(item)
171-
return json.dumps({ 'items': queryList })
226+
return "", json.dumps({ 'items': queryList })
172227

173228
def getByIndex(self, keywordIndex):
174229
keywordIndex = int(keywordIndex)
@@ -185,7 +240,7 @@ def getByIndex(self, keywordIndex):
185240
else:
186241
self.args.append(f"'{item['host']}'")
187242

188-
return " ".join(self.args)
243+
return item['name'], " ".join(self.args)
189244
except IndexError:
190245
return 'Execute Failed! Server may be remove!'
191246

0 commit comments

Comments
 (0)