I am trying to configure my .tmux.conf to display a scrolling string of text. For what it is worth, the scrolling text is an aviation weather observation that is scraped using a really ugly bash script that is defined in .zshrc as follows:
function scrollMetar {
curl -s "https://www.aviationweather.gov/metar/data?ids=kjyo&format=raw&date=&hours=0" | awk '/Data\ starts\ here/{getline; print}' | html2text | zscroll -l 14 -n 0
}
I want to take the scrolling output from the scrollMetar command and have that scroll on the tmux status line.
My current .tmux.conf section looks like this:
set-option -g status-left "\
#[fg=colour7, bg=colour241]#{?client_prefix,#[bg=colour167],} ❐ #S \
#[fg=colour241, bg=colour237] \
#(echo 'TEST TEXT') \
#{?window_zoomed_flag, 🔍,} "
Where the echo 'TEST TEXT' is should be where the scrollMetar would go, but when inserted doesn't output anything.
I am guessing that this maybe a limitation of tmux, but I would be grateful for any advice and I am completely open to alternate implementations.
Okay, so it seems like .tmux.conf did not like calling the function, or could not find it. Putting the function in a executable shell script fixed the problem.
Related
Is there a way to issue a command to close all tmux windows unless something is open in that window? For example, an open file, a running process, etc.?
I am hoping for something that functions as a web browser where you can right click and select close all other tabs to the right. I'd like to issue this in tmux, and similar to the web browser example, have "busy" windows or panes prompt me to close them or silently fail to close.
I have seen this question, but I don't necessarily want to issue the command to all windows.
Here's a shell alternative:
for win_id in $(tmux list-windows -F '#{window_active} #{window_id}' | awk '/^1/ { active=1; next } active { print $2 }'); do tmux kill-window -t "$win_id"; done
And here's the same (readable version):
for win_id in $(tmux list-windows -F '#{window_active} #{window_id}' | \
awk '/^1/ { active=1; next } active { print $2 }')
do
tmux kill-window -t "$win_id"
done
Edit: I made a plugin with this!
https://github.com/pschmitt/tmux-forsaken
I just built a script to do so, here it is:
#!/usr/bin/env python3
import subprocess
import os
import re
result = subprocess.run(['tmux', 'list-windows'], stdout=subprocess.PIPE)
result = result.stdout.decode('utf-8')
lines = result.splitlines()
should_close_next = False
for line in lines:
if should_close_next:
window = line.split(':')[0]
os.system(f'tmux kill-window -t {window}')
continue
match = re.search("active", line)
if match:
should_close_next = True
And to integrate it with your tmux add to your tmux.conf
bind-key "k" run-shell "kill_panes_to_right.py\n"
Best
Sometimes I use multiline commands in zsh:
❯ echo \
> a \
> multiline \
> command
When editing the command after pulling it from a history search, I can change the content of individual lines. However, I can't figure out how to insert another line:
# I want to insert another line after "multiline"...
❯ echo \
> a \
> multiline \ # but hitting <return> here just runs the command, even though there's a backslash at the end of the line
> command
How can I insert a newline in the middle of a multiline command pulled from history?
You can use ESC-Return.
FWIW, I tested it on Debian Jessie, zsh 5.0.7 and it works there.
You can use self-insert-unmeta to bind Alt+Return to insert a literal newline without accepting the command:
bindkey '^[^M' self-insert-unmeta
To use your example: Hitting Alt+Return at the cursor position (#)
% echo \
a \
multiline \#
command
will get you this:
% echo \
a \
multiline \
#
command
This works not only when editing history, but also when typing commands. So you can prepare several commands in a script like fashion and accept them with a single Return.
For example pressing Alt+Return instead of # in this example:
% echo command 1#
echo command 2#
echo command 3
will do the same thing as the command echo command 1; echo command 2; echo command 3 and produce this output:
command 1
command 2
command 3
(A summary of answers from https://unix.stackexchange.com/questions/6620/how-to-edit-command-line-in-full-screen-editor-in-zsh)
zsh comes with a function that can be used to open the current command line in your favorite editor. Add the following lines to your .zshrc:
autoload -z edit-command-line
zle -N edit-command-line
bindkey "^X^E" edit-command-line
The first line loads the function. The second line creates a new widget for the Z shell line editor (zle) from the function of the same name. The third line binds the widget to Control-X Control-E. If you use the vi bindings rather than emacs key bindings, use something like
bindkey -M vicmd v edit-command-line
instead (which binds the widget to v in vicmd mode).
If using bindkey -v mode, you can also use the default o/O commands from vicmd mode to add a newline line and enter insert mode in it, respectively above or below the current line.
Just to note, if you want to comment in a multiline command, you could use:
❯ echo `#first comment` \
a `#second comment` \
multiline \
command
CTRL + Enter (Return) for Windows/WSL
CTRL +X CTRL+E for Mac
Edited as per the comment below
Sounds like an appropriate place to use a shell script file instead no?
#!/bin/zsh
my
commands
here
I can even add a new line at a later time.
Suppose have 3 panes in a tmux window: vim, vom, and vam
I want to access the pane title of the first pane as part of a keyboard mapping (forward command to vim if vim's in pane 1). It wasn't working as expected and I've narrowed it down to the following...
If I run:
tmux display-message "`tmux list-panes -F '#{pane_title}'`"
the result is:
vim
vom
vam
This is what I'd expect. If I try to run the same from a key mapping:
bind -n C-h run "tmux display-message \"`tmux list-panes -F '#{pane_title}'`\""
I get the title of the current pane repeated three times:
vom
vom
vom
Does run-shell execute in a different context or something?
Thanks for your help
Run tmux list-keys in the terminal and see what C-h gets mapped to. I get something like this:
bind-key C-t run-shell "tmux display-message "name1
name2
name3""
From the above, you can see the backtick interpolation happens at the moment when the key is bound, not later when the binding is executed.
I don't know how to get around this and you must be having a lot of pain because of so many nested commands.
Personally, when hacking tmux I always apply the rule of "get to the shell as soon as possible".
For your example that would mean:
keep the key binding simple: bind -n C-h run "/path/to/script.sh"
create a script, make it executable and put the rest of what you want to do in it. This would be its content:
tmux display-message "`tmux list-panes -F '#{pane_title}'\`"
I just did it and it worked for me locally. Hope that helps!
Can anybody explain this behaviour of the bash shell which is driving me nuts
[root#ns1 bin]# export test=`whois -h whois.lacnic.net 187.14.6.108 | grep -i inetnum: | awk '{print $2}'`
[root#ns1 bin]# echo $test
187.12/14
[root#ns1 bin]# echo "iptables -I INPUT -s $test -J DROP"
-J DROP -I INPUT -s 187.12/14
[root#ns1 bin]#
Why is my echo screwed up? It is being changed by the contents of $test.
If you change $test to "ABC" all is fine. Is it related to the slash?
Why is my echo screwed up? It is being changed by the contents of
$test.
Because your test contains a carriage return. Remove it:
test=$(whois -h whois.lacnic.net 187.14.6.108 | grep -i inetnum: | awk '{print $2}' | tr -d '\r')
Your test contains something like
1234567 -I INPUT -s 187.12/14\r-J DROP
which, due to the carriage return, is visible only as
-J DROP -I INPUT -s 187.12/14
The CR moves the cursor to the start-of-line, where it then overwrites previous characters.
You could try
echo "$test" | od -bc
to verify this.
This is almost certainly a carriage return. echo is doing its job correctly and emitting the string to your terminal; the problem is that your terminal is treating a part of the string as a command for it to follow (specifically, a LF character, $'\r', telling it to send the cursor to the beginning of the existing line).
If you want to see the contents of $test in a way which doesn't allow your terminal to interpret escape sequences or other control characters, run the following (note that the %q format string is a bash extension, not available in pure-POSIX systems):
printf '%q\n' "$test"
This will show you the precise contents formatted and escaped for use by the shell, which will be illuminative as to why they are problematic.
To remove $'\r', which is almost certainly the character giving you trouble, you can run the following parameter expansion:
test=${test//$'\r'/}
Unlike solutions requiring piping launching an extra process (such as tr), this happens inside the already-running bash shell, and is thus more efficient.
As you know version 2 of TextMate is on the way and the current development version is very promising: https://github.com/textmate/textmate/blob/master/README.md
In my case I am using R in terminal (MacOSX Mountain Lion) and I develop my code with TextMate2. With the previous version of TextMate (1.5.11) I used the following trick to send selected text or lines to my terminal window:
-> See How can I send selected text (or a line) in TextMate to R running on Terminal
This trick worked perfectly for me but I cannot figure out how to get a similar behaviour with TextMate2.
Any idea? I thank you in advance for your precious help.
Actually based on a previous answer (How can I send selected text (or a line) in TextMate to R running on Terminal), I created my own Bundle in TextMate 2 using the following code:
#!/bin/bash
source "$TM_SUPPORT_PATH/lib/bash_init.sh" # might not be necessary
# input is selection or document
rawText="$(cat | sed 's/ / /g;')"
osascript -e 'on run(theCode)' \
-e ' tell application "Terminal"' \
-e ' do script theCode in window 1' \
-e ' end tell' \
-e 'end run' -- "$rawText"
open "txmt://open?line=$(($TM_LINE_NUMBER+1))&column=1000000" &
See the screenchot below.
The only problem is that when you select a chunk of text, the cursor is jumping to the first line of the document, which is a very irritating behaviour. Changing 'Input" from 'Line' to 'Selection' doe not solve the issue.
Any thoughts?
This works for me, and it correctly goes to the end of the selection.
I just added the osascript part in the previous answer, and put it in the code that was in the original R bundle written by Hans-Jörg Bibiko.
Set "scope selector" to "source.r" and "output" to "discard".
Set "Input" to "line" and it does what I need: send the line if nothing is selected, and send the selection otherwise.
edit: it works perfectly with selections, but not with line. When you do not select text it just re-runs everything from the top of the file
edit2: solved, I wrote to Hans-Jörg Bibiko and he pointed me to the "Input" selection.
#!/usr/bin/env bash
# input is selection or document
rawText="$(cat | sed 's/ / /g;')"
curDir=''
if [[ ${#TM_DIRECTORY} -gt 0 ]]; then
curDir="$TM_DIRECTORY"
fi
osascript -e 'on run(theCode)' \
-e ' tell application "Terminal"' \
-e ' do script theCode in window 1' \
-e ' end tell' \
-e 'end run' -- "$rawText"
if [ "$TM_LINE_NUMBER" != "" ]; then
"$TM_MATE" -l "$(($TM_LINE_NUMBER+1)):1000000"
elif [[ $TM_SELECTION =~ [1-9][0-9]*:?[0-9]*-([1-9][0-9]*):?[0-9]* ]]; then
# Regular Selection
"$TM_MATE" -l "$((${BASH_REMATCH[1]}+1)):1000000"
elif [[ $TM_SELECTION =~ [1-9][0-9]*:?[0-9]*x([1-9][0-9]*):?[0-9]* ]]; then
# Block (option) selection
"$TM_MATE" -l "$((${BASH_REMATCH[1]}+1)):1000000"
else
"$TM_MATE"
fi
A bit of an indirect answer : I use the R bundle in Textmate 2 (which also worked in Textmate 1). Just select the lines you want to run and "Send selection to / R App" ( I have it binded to command-R but I'm not sure if it's the original binding)
First time it opens the R app and execute code. Subsequent times it just pastes the code and run it.
It's not exactly "send to terminal" but still works
I got it working with a few changes on bhaibeka's answer. Apparently $TM_LINE_NUMBER is empty and that makes the cursor jump to the first line of the document. By getting rid of the last line, it solves part of the problem.
#!/bin/bash
[[ -f "${TM_SUPPORT_PATH}/lib/bash_init.sh" ]] && . "${TM_SUPPORT_PATH}/lib/bash_init.sh"
rawText="`cat`"
osascript -e 'on run(theCode)' \
-e ' tell application "Terminal"' \
-e ' do script theCode in window 1' \
-e ' end tell' \
-e 'end run' -- "$rawText" > /dev/null
The other problem is how to move the cursor to the end of the selection. I made it work by inserting the 'empty' output at the end of the selection (on the right panel: Output:"Insert After Input" and Format: "Text"). Probably this is not the most elegant way to do it but it works.