<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>emre şahin's digital garden 🍃 - terminal</title>
    <link>https://emresahin.net/tags/terminal/</link>
    <description>Posts in the terminal tag</description>
    <language>en</language>
    <managingEditor>contact@emresahin.net (Emre Şahin)</managingEditor>
    <lastBuildDate>Tue, 15 Sep 2026 19:46:32 +0000</lastBuildDate>
    <atom:link href="https://emresahin.net/tags/terminal/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>devlog 31</title>
      <published>2025-06-07T10:29:03+00:00</published>
      <updated>2025-06-07T10:29:03+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Sat, 07 Jun 2025 10:29:03 +0000</pubDate>
      <link>https://emresahin.net/devlog-31/</link>
      <guid isPermaLink="true">https://emresahin.net/devlog-31/</guid>
      <description>🐢 I think sending Alt keys in Ghostty needs some love. Let’s start with it as an easy task for the day. 🐇 While checking macos-option-as-alt as a potential source of the problem, I spent time adjusting the Ghostty icon . I changed the app icon. This is how I spend my time being extremely producti...</description>
      <category>shell</category>
      <category>tmux</category>
      <category>ghostty</category>
      <category>productivity</category>
      <category>macos</category>
      <category>terminal</category>
      <content:encoded><![CDATA[<p>🐢 I think sending Alt keys in Ghostty needs some love. Let’s start with it as an easy task for the day.</p>
<p>🐇 While checking <a href="https://ghostty.org/docs/config/reference#macos-option-as-alt"><code>macos-option-as-alt</code></a> as a potential source of the problem, I spent time <a href="https://ghostty.org/docs/config/reference#macos-icon">adjusting the Ghostty icon</a>. I changed the app icon. This is how I spend my time being extremely productive.</p>
<p>🐢 Weird. The <code>Option as alt</code> key setting is fine.</p>
<p>🐇 Actually, the Alt key works; the reason we cannot make panes larger is that <code>Alt-Right</code> and <code>Alt-Left</code> are not bound to this.</p>
<p>🐢 You may be right, yes. Then, what’s the key to enlarge a pane?</p>
<p>🦊 List all the keys. Check the keys. You should have done this already.</p>
<pre><code class="language-shell">$ tmux list-keys | rg resize

bind-key    -T prefix       &gt;                      display-menu -T "#[align=centre]#{pane_index} (#{pane_id})" -x P -y P "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}" &lt; { send-keys -X history-top } "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}" &gt; { send-keys -X history-bottom } '' "#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}" C-r { if-shell -F "#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}" "copy-mode -t=" ; send-keys -X -t = search-backward "#{q:mouse_word}" } "#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}" C-y { copy-mode -q ; send-keys -l "#{q:mouse_word}" } "#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}" c { copy-mode -q ; set-buffer "#{q:mouse_word}" } "#{?mouse_line,Copy Line,}" l { copy-mode -q ; set-buffer "#{q:mouse_line}" } '' "#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}" C-h { copy-mode -q ; send-keys -l "#{q:mouse_hyperlink}" } "#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}" h { copy-mode -q ; set-buffer "#{q:mouse_hyperlink}" } '' "Horizontal Split" h { split-window -h } "Vertical Split" v { split-window -v } '' "#{?#{&gt;:#{window_panes},1},,-}Swap Up" u { swap-pane -U } "#{?#{&gt;:#{window_panes},1},,-}Swap Down" d { swap-pane -D } "#{?pane_marked_set,,-}Swap Marked" s { swap-pane } '' Kill X { kill-pane } Respawn R { respawn-pane -k } "#{?pane_marked,Unmark,Mark}" m { select-pane -m } "#{?#{&gt;:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}" z { resize-pane -Z }
bind-key    -T prefix       z                      resize-pane -Z
bind-key -r -T prefix       M-Up                   resize-pane -U 5
bind-key -r -T prefix       M-Down                 resize-pane -D 5
bind-key -r -T prefix       M-Left                 resize-pane -L 5
bind-key -r -T prefix       C-Up                   resize-pane -U
bind-key -r -T prefix       C-Down                 resize-pane -D
bind-key -r -T prefix       C-Left                 resize-pane -L
bind-key -r -T prefix       C-Right                resize-pane -R
bind-key    -T root         MouseDown3Pane         if-shell -F -t = "#{||:#{mouse_any_flag},#{&amp;&amp;:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}" { select-pane -t = ; send-keys -M } { display-menu -T "#[align=centre]#{pane_index} (#{pane_id})" -t = -x M -y M "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}" &lt; { send-keys -X history-top } "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}" &gt; { send-keys -X history-bottom } '' "#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}" C-r { if-shell -F "#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}" "copy-mode -t=" ; send-keys -X -t = search-backward "#{q:mouse_word}" } "#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}" C-y { copy-mode -q ; send-keys -l "#{q:mouse_word}" } "#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}" c { copy-mode -q ; set-buffer "#{q:mouse_word}" } "#{?mouse_line,Copy Line,}" l { copy-mode -q ; set-buffer "#{q:mouse_line}" } '' "#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}" C-h { copy-mode -q ; send-keys -l "#{q:mouse_hyperlink}" } "#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}" h { copy-mode -q ; set-buffer "#{q:mouse_hyperlink}" } '' "Horizontal Split" h { split-window -h } "Vertical Split" v { split-window -v } '' "#{?#{&gt;:#{window_panes},1},,-}Swap Up" u { swap-pane -U } "#{?#{&gt;:#{window_panes},1},,-}Swap Down" d { swap-pane -D } "#{?pane_marked_set,,-}Swap Marked" s { swap-pane } '' Kill X { kill-pane } Respawn R { respawn-pane -k } "#{?pane_marked,Unmark,Mark}" m { select-pane -m } "#{?#{&gt;:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}" z { resize-pane -Z } }
bind-key    -T root         MouseDrag1Border       resize-pane -M
bind-key    -T root         M-MouseDown3Pane       display-menu -T "#[align=centre]#{pane_index} (#{pane_id})" -t = -x M -y M "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}" &lt; { send-keys -X history-top } "#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}" &gt; { send-keys -X history-bottom } '' "#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}" C-r { if-shell -F "#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}" "copy-mode -t=" ; send-keys -X -t = search-backward "#{q:mouse_word}" } "#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}" C-y { copy-mode -q ; send-keys -l "#{q:mouse_word}" } "#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}" c { copy-mode -q ; set-buffer "#{q:mouse_word}" } "#{?mouse_line,Copy Line,}" l { copy-mode -q ; set-buffer "#{q:mouse_line}" } '' "#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}" C-h { copy-mode -q ; send-keys -l "#{q:mouse_hyperlink}" } "#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}" h { copy-mode -q ; set-buffer "#{q:mouse_hyperlink}" } '' "Horizontal Split" h { split-window -h } "Vertical Split" v { split-window -v } '' "#{?#{&gt;:#{window_panes},1},,-}Swap Up" u { swap-pane -U } "#{?#{&gt;:#{window_panes},1},,-}Swap Down" d { swap-pane -D } "#{?pane_marked_set,,-}Swap Marked" s { swap-pane } '' Kill X { kill-pane } Respawn R { respawn-pane -k } "#{?pane_marked,Unmark,Mark}" m { select-pane -m } "#{?#{&gt;:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}" z { resize-pane -Z }
</code></pre>
<p>🐇 <code>resize-pane</code> has keys, but they conflict with <code>C-Right</code>, etc., which are macOS display selection keys. I defined <code>M-S-Right</code>, etc., to resize and <code>M-C-Right</code>, etc., to swap the panes. Defining new keys with <code>M-S</code>…</p>
<pre><code class="language-tmux">bind-key -n "M-S-Right" resize-pane -R 10
bind-key -n "M-S-Left" resize-pane -L 10
bind-key -n "M-S-Up" resize-pane -U 10
bind-key -n "M-S-Down" resize-pane -D 10
</code></pre>
<p>🐢 We can set keys to swap windows too, maybe to <code>M-C-PageDown</code>, etc. <code>M-PageDown</code> now moves between windows.</p>
<p>🐇 Let’s take a look at the command options:</p>
<pre><code class="language-text">     swap-window [-d] [-s src-window] [-t dst-window]
                   (alias: swapw)
             This is similar to link-window, except the source and destination windows are swapped.  It is an error if no window exists at src-window.  If -d is given, the new window
             does not become the current window.

             If -s is omitted and a marked pane is present (see select-pane -m), the window containing the marked pane is used rather than the current window.
</code></pre>
<p>🐢 The use case will be limited, though.</p>
<p>🐇 Umm, right. Let’s stop procrastinating here.</p>
<p>🐢 It was productive procrastination, though. Now I can resize my tmux panes.</p>]]></content:encoded>
    </item>
    <item>
      <title>Nushell $env.PATH in tmux</title>
      <published>2025-05-30T16:09:29+00:00</published>
      <updated>2025-05-30T16:09:29+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Fri, 30 May 2025 16:09:29 +0000</pubDate>
      <link>https://emresahin.net/nushell--env-path-in-tmux/</link>
      <guid isPermaLink="true">https://emresahin.net/nushell--env-path-in-tmux/</guid>
      <description>I noticed that when I use: set -g default-shell nu in .tmux.conf to specify Nushell as the shell, it doesn’t load $env.PATH . It is necessary to specify the shell with: set -g default-command nu -l (using the full path to nu ) to ensure the shell reads your configuration file.</description>
      <category>Shell</category>
      <category>Nushell</category>
      <category>Tmux</category>
      <category>Terminal</category>
      <category>Configuration</category>
      <content:encoded><![CDATA[<p>I noticed that when I use:</p>
<pre><code class="language-tmux">set -g default-shell nu
</code></pre>
<p>in <code>.tmux.conf</code> to specify Nushell as the shell, it doesn’t load <code>$env.PATH</code>. It is necessary to specify the shell with:</p>
<pre><code class="language-tmux">set -g default-command nu -l
</code></pre>
<p>(using the full path to <code>nu</code>) to ensure the shell reads your configuration file.</p>]]></content:encoded>
    </item>
    <item>
      <title>airmux</title>
      <published>2024-01-25T09:01:54+00:00</published>
      <updated>2024-01-25T09:01:54+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Thu, 25 Jan 2024 09:01:54 +0000</pubDate>
      <link>https://emresahin.net/airmux/</link>
      <guid isPermaLink="true">https://emresahin.net/airmux/</guid>
      <description>Airmux is a session manager for tmux that allows defining and managing multiple tmux sessions through project configuration files. Projects are defined in YAML or JSON files that specify settings such as commands to run, window/pane layouts, and other session settings. The start command loads and...</description>
      <category>tools</category>
      <category>tools</category>
      <category>tmux</category>
      <category>cli</category>
      <category>rust</category>
      <category>airmux</category>
      <category>terminal</category>
      <content:encoded><![CDATA[<ul>
<li><a href="https://github.com/dermoumi/airmux">Airmux</a> is a session manager for tmux that allows defining and managing multiple tmux sessions through project configuration files.</li>
<li>Projects are defined in YAML or JSON files that specify settings such as commands to run, window/pane layouts, and other session settings.</li>
<li>The <code>start</code> command loads and attaches to an existing project, while <code>edit</code> creates or modifies project files.</li>
<li>Projects support environment variable expansion, and command-line arguments passed to <code>start</code> are available as <code>$1</code>, <code>$2</code>, etc., in the project file.</li>
<li>Local project files can be used without specifying a name if they are found by searching parent directories.</li>
<li>Commands like <code>list</code>, <code>remove</code>, and <code>freeze</code> can manage existing projects.</li>
<li><code>Debug</code> prints the tmux commands to create a session without attaching, which is useful for troubleshooting.</li>
<li>Fields like <code>on_start</code> and <code>on_stop</code> allow running commands before or after session startup/shutdown.</li>
<li>Windows and panes have their own settings, such as layouts and commands to run, and they can be nested in the project file.</li>
<li>Airmux aims to provide an easy and organized way to define and manage multiple related tmux sessions through project files.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Find Which Process is Listening on a Port</title>
      <published>2023-03-14T10:45:00+00:00</published>
      <updated>2023-03-14T10:45:00+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Tue, 14 Mar 2023 10:45:00 +0000</pubDate>
      <link>https://emresahin.net/find-which-process-listens-to-a-port/</link>
      <guid isPermaLink="true">https://emresahin.net/find-which-process-listens-to-a-port/</guid>
      <description>Sometimes I need to find out which process is listening on a specific port, usually so I can kill it. On macOS: sudo lsof -i -P | grep LISTEN | grep :$PORT And on Linux: netstat -pntl | grep $PORT</description>
      <category>Bits</category>
      <category>Networking</category>
      <category>SysAdmin</category>
      <category>macos</category>
      <category>linux</category>
      <category>netstat</category>
      <category>lsof</category>
      <category>devops</category>
      <category>terminal</category>
      <content:encoded><![CDATA[<p>Sometimes I need to find out which process is listening on a specific port, usually so I can kill it.</p>
<p>On macOS:</p>
<pre><code class="language-bash">sudo lsof -i -P | grep LISTEN | grep :$PORT
</code></pre>
<p>And on Linux:</p>
<pre><code class="language-bash">netstat -pntl | grep $PORT
</code></pre>]]></content:encoded>
    </item>
  </channel>
</rss>
