#CLI

Nick | OneThingWell.dev's avatar
Nick | OneThingWell.dev

@unixroot@indieweb.social

To prevent git from finishing the current commit/operation, your editor needs to exit with a non-zero status. In vim, you can use :cq to do that.

Nick | OneThingWell.dev's avatar
Nick | OneThingWell.dev

@unixroot@indieweb.social

To prevent git from finishing the current commit/operation, your editor needs to exit with a non-zero status. In vim, you can use :cq to do that.

Jaeyeol Lee's avatar
Jaeyeol Lee

@kodingwarrior@hackers.pub

이 글(그리고 후속작이 될 글들)은, 내 개발환경에서 자주 사용하고 있고 실제로도 애정하고 있는 도구에 대해서 소개하게 될 것 같다. 내가 어떤 환경에서 개발하고 있는지 궁금한 분들은 내 dotfiles 리포지토리를 참고해도 좋을 것 같다.

먼저, dotfiles란 무엇인가?

dotfiles라는 이름 자체만 보면 뭔가 대단해보일 것 같지만, dotfiles라는 이름 자체는 그냥 단순하다.

  • 어딘가의 가이드라인에서 지시하는대로 개발환경을 세팅하다보면, .zshrc/.bashrc 같은 것들을 마주하게 될 것이다.
  • git을 사용하고 있는 사람이라면, 어떤 diff 도구(delta, difft)를 사용할지, 어떤 alias 명령어를 등록할지 같은 것들을 명시하기 위해서 .gitconfig 같은 파일을 수정하게 될 때가 있다.
    • 물론, 이런것보다는 git config pull.rebase true 같은 명령어를 실행하는 경우가 더 많을 수 있다. 하지만, 이런 명령어를 실행하면 .gitconfig에도 그대로 기록이 된다.

위에서 언급한 예시를 보면 알 수 있겠듯이, 앞에 dot(.)이 붙어있는 설정파일이라면 dotfiles라고 할 수 있겠다. dotfiles 리포지토리를 만들어서 관리를 하는 이유는 무엇인가? 그것은 바로 어떤 환경에서든 .zshrc/.gitignore 파일 같은 것들을 동일하게 사용하여 작업의 흐름을 온전히 유지할 수 있다는 장점이 있기 때문이다. dotfiles를 git과 같은 버전관리 도구로 관리할 수 있고, github 같은 저장소에 올려놓을 수 있다면.... 어떤 개발환경으로 갈아타더라도 github에서 바로 내려받고, 각 설정파일들을 옮기면 그만이기 때문에 개발환경 설정하는데 드는 시간적 비용을 굉장히 아낄 수 있다.

dotfiles를 관리하는 방법들은 여러가지 있겠지만(symbolic link를 이용한다던가 등등), 개인적으로는 chezmoi를 권장하는 바이다. chezmoi는 dotfiles들을 버전관리할 수 있게 편의성을 제공해주는 CLI 도구이다.

  • 나도 chezmoi를 엄청 애용하고 있기 때문에, 내 dotfiles를 실제로 사용해보고 싶다면, chezmoi init https://github.com/malkoG/dotfiles.git 명령을 실행해보면 된다.

다시, 본론으로 Wezterm에 대해서 알아보자.

Wezterm은 Konsole/iTerm2/Gnome Terminal/Alacritty과 같은 터미널 에뮬레이터이며, Rust 기반으로 구축이 되어 있고, GPU 가속을 지원한다. 따라서, 렌더링 자체도 어느 정도는 빠른 편이다.

주변 사람들에게 한번 써보도록 권장하는 터미널 에뮬레이터가 세 가지 정도 있는데, Alacritty/Kitty 그리고 이 글에서 소개하는 Wezterm 정도 된다. 요즘은 Zig 기반으로 만들어진 Ghostty[1]도 추천할만 한 것 같다. 하지만, 이 글에서는 Wezterm을 소개하기로 했기 때문에, Wezterm 중심으로 소개하도록 하겠다.

Wezterm은 다음과 같은 특징을 가진다.

  • Linux, MacOS, 윈도우즈, FreeBSD 다양한 환경에서 돌아간다.
  • 한 윈도우를 여러개의 pane으로 쪼개서 분할하여 멀티플렉싱을 지원한다.(물론, 나는 ZelliJ/Tmux를 쓰기때문에 잘 이용하지는 않는 기능이다.
  • 마우스 지원이 잘 된다
  • 터미널에 표시되는 글자를 캡쳐해서 하이퍼링크로 치환이 가능하다.
    • 이건 나도 잘 이용하지는 않는 기능이지만.. T0010 같은 코드가 화면 상에 보여진다면, 특정 린터 페이지의 설명화면으로 이동하는 링크를 심을 수 있다. kiyoon님의 dotfiles 참고
  • lua로 스크립팅이 가능한데, 활용할 수 있는 방향이 굉장히 다양하다.
    • 여기에서 설명한 기능들을 최대한 활용하여 스크립팅이 가능하다.
    • API 문서를 슥 훑어보았을때, "어? 설마 이게 되나?" 싶은 생각이 든다면, 여러분이 생각하는 것도 아마 가능할지도 모른다.

Wezterm, 써보자.

Wezterm을 설치한다면 설치 안내 페이지를 참고해서 설치하면 되는데, 여러분이 Wezterm을 설치했다면 당장은 검은 화면만 뜰지도 모른다.

Wezterm을 설치하고 나서, .config/wezterm/wezterm.lua 파일을 수정해야 하는데, 당장은 아래처럼 비어있을 것이다. 파일이 없다면 만들어두는 것이 좋다.

return {}

위의 코드에서 {}는 lua에서는 테이블(다른 언어로 치면, 딕셔너리/오브젝트 같은 것)이지만, wezterm 터미널의 configuration을 나타내는 테이블이다. 여기에 몇가지 추가사항을 넣어보겠다.

터미널 에뮬레이터를 설치했는데, 터미널 에뮬레이터를 설치했으면 가장 처음부터 하는게 무엇이겠는가? 바로, 폰트를 세팅하는 것이다. 터미널 환경에서 작업할때 폰트만큼 중요한게 또 없다.

local wezterm = require("wezterm")

return {
	font = wezterm.font_with_fallback({'Cascadia Code NF', 'NanumBarunGothic'}),
	font_size = 12.0,
	line_height = 1.2,
}

폰트를 가져다 쓸때는 위의 예시와 같이 font_with_fallback 함수를 이용해서 가져다 쓸 수 있고, 그 외에도 폰트 크기를 지정하거나 행간을 지정할 수도 있다. 공식페이지에서 보았듯이, 여러분의 취향에 따라 배경색 혹은 배경이미지도 지정할 수 있는데 여러분 나름대로의 기준이 있고 욕심이 난다면 한번 도전해보는 것도 나쁘지 않을 것 같다.

위의 코드를 복사 붙여넣고 편집하다보면 느낄 수 있겠지만, wezterm은 설정파일을 편집할때 Hot Reloading을 지원한다. 이 또한, 내가 가장 애정하는 기능 중 하나이다. 혹여나 wezterm 설정 파일을 수정했을때, 문법에 오류가 있거나 설정값을 잘못 지정했을 때, 새 창으로 어떤 부분에 오류가 있는지 친절하게 Alert도 띄워준다.

API 레퍼런스를 보기만 해도 스크립팅으로 기능을 확장할 수 있는 가능성이야 당연히 많긴 하겠지만, 처음 접하는 입장에서는 어떻게 커스터마이징할 지 파악하기 난해할 수 있다.

아래에서는 내가 어떻게 Wezterm을 커스터마이징을 하고 있는지 예시를 나열하는 것으로 글을 끝내겠다. Wezterm, 믿고 써보시라.

내가 Wezterm을 응용하는 방법

1. 반투명도 조정하기

Wezterm에서 터미널 색상을 설정할때, 배경색상의 반투명도를 지정할 수 있는 옵션이 있다. 나는 여기서 단축키를 입력했을때 반투명도를 동적으로 조절하고 싶었다.

반투명도를 상수로 둘 수는 있지만, 모니터 하나 짜리의 환경에서 작업한다면 브라우저를 뒤쪽에 두고 터미널 앱을 앞에 두는 식으로 작업을 많이 하게 된다. HMR(Hot Module Reloading)이 되는 개발환경이라면, 소스코드를 편집하고 화면에 즉각적으로 반영이 되는걸 기대할텐데 이걸 탭 스위칭하면서 확인하기는 굉장히 번거롭다. 온전히 작업을 유지하다가 잠깐 확인하고 싶을때 반투명도를 변경하면 되는데도 말이다.

Wezterm에서는 이벤트를 발신할 수 있고, 다른 프로세스에서 특정 이벤트를 수신했을때 어떤 동작을 할 것인지를 정의할 수 있다. Wezterm 터미널 옵션을 수정하는것도 여기에 포함될 수 있다. 특정 단축키를 입력하면, 어떤 이벤트를 발생시킬 수 있고, 그 이벤트로 인해서 화면의 반투명도를 조정할 수 있게 했다.

local default_opacity = 0.9

local keymaps = {}

-- SHIFT + CTRL + Z 키를 누르면 반투명도를 감소시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = "Z",
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'decrease-opacity',
  }
)

-- SHIFT + CTRL + X 키를 누르면 반투명도를 증가시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = 'X',
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'increase-opacity',
  }
)


-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('increase-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity
  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity + 0.1
  if opacity > 1.0 then
	opacity = 1.0
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('decrease-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity

  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity - 0.1
  if opacity < 0.3 then
	opacity = 0.3
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

return {
  keys = keymaps
}

2. 탭 이름 변경하기

대부분 터미널 에뮬레이터에서 탭 이름을 표시할때, 현재 탭에서 돌고 있는 프로세스의 이름을 명시할때가 많다. 그런데, 탭에 명시되어 있는 타이틀만 가지고는 각각의 탭이 어떤 역할을 하는 것인지 파악하기 어렵다. 어느 쪽이 서버를 띄우고 있는건지, 어느 쪽이 에디터 편집 화면인지, 어느 쪽이 LLM Agent를 돌리고 있는지 난해하다.

하지만, 아래처럼 wezterm.action.PromptInputLine API를 사용해서 프롬프트 입력을 받은 내용을 기반으로, 현재 활성화된 탭의 이름을 변경하는 식으로 인지부하를 줄일 수 있다.

local wezterm = require('wezterm')
local keymaps = {}

table.insert(
  keymaps,
  {
	key = '`',
	mods = 'CTRL',
	action = wezterm.action.PromptInputLine {
	  description = "Enter new name for tab",
	  action = wezterm.action_callback(function(window, _, line)
	    if line then
		  window:active_tab():set_title(line)
		end
	  end)
	}
  }
)

return {
  keys = keymaps
}

3. BEEP음 대신 화면이 번쩍이게 하기

Aider나 Claude Code 같은 LLM 에이전트가 작업을 수행 후 아예 작업이 끝났거나, 혹은 작업에 대한 승인을 요구할 때가 간혹 있다. LLM 에이전트가 작업을 수행하는걸 가만히 보고만 있을 순 없을 것이다.

Claude Code/Aider는 다행히도 응답을 하고 나서 추가적인 명령을 실행할 수 있는 옵션[2]을 제공해주는데, 거기에 간단하게 echo -ne '\007' 명령어를 넘겨줄 수 있다. 이 명령어는 엄청 어렵지는 않다. 터미널 앱에 내장된 시스템 벨 소리를 재생하는 명령어다.

작업 환경이 어디냐에 따라 다를 순 있겠지만, 작업 완료 여부를 음성으로 받기에는 물리적인 제약이 있을 수 있다. 아예 알림 센터를 이용한다고 치자. 업무 시간대에 방해금지 모드를 설정했다면 알림이 울리게 설정이 했더라도 시스템 제약상 묻힐 가능성도 있다.[3]

visual_bell 옵션을 활용하면, 터미널에 내장된 시스템 벨 소리를 울리는 대신 화면이 반짝이게 해서 다른 에이전트가 응답을 완료했다고 명시적으로 알림을 받을 수 있다. LLM 에이전트가 하는 일을 일일이 모니터링하지 않더라도, 다른 작업을 수행하는 중에 화면이 반짝이면 그때 확인하기만 하면 그만이다.

return {
	colors = {
		visual_bell = '#003355',
	},

	visual_bell = {
		fade_in_duration_ms  = 75,
		fade_out_duration_ms = 75,
		target               = 'BackgroundColor', -- 또는 'CursorColor'
	}
}

  1. Hashicorp 공동창업자인 Mitchell Hashimoto가 만든 터미널 에뮬레이터인데, OpenAI에서 Codex 시연할때 Ghostty 터미널로 시연한 바가 있다. ↩︎

  2. Aider는 notifications-command, Claude Code는 Hook이 있다 ↩︎

  3. 어떤 사람은 휴대전화를 진동모드로 해놓고, 텔레그램/디스코드로 알림쏴서 알림을 수신받는 방식을 쓰고 있는 것을 관찰한 바는 있다. ↩︎

Jaeyeol Lee's avatar
Jaeyeol Lee

@kodingwarrior@hackers.pub

이 글(그리고 후속작이 될 글들)은, 내 개발환경에서 자주 사용하고 있고 실제로도 애정하고 있는 도구에 대해서 소개하게 될 것 같다. 내가 어떤 환경에서 개발하고 있는지 궁금한 분들은 내 dotfiles 리포지토리를 참고해도 좋을 것 같다.

먼저, dotfiles란 무엇인가?

dotfiles라는 이름 자체만 보면 뭔가 대단해보일 것 같지만, dotfiles라는 이름 자체는 그냥 단순하다.

  • 어딘가의 가이드라인에서 지시하는대로 개발환경을 세팅하다보면, .zshrc/.bashrc 같은 것들을 마주하게 될 것이다.
  • git을 사용하고 있는 사람이라면, 어떤 diff 도구(delta, difft)를 사용할지, 어떤 alias 명령어를 등록할지 같은 것들을 명시하기 위해서 .gitconfig 같은 파일을 수정하게 될 때가 있다.
    • 물론, 이런것보다는 git config pull.rebase true 같은 명령어를 실행하는 경우가 더 많을 수 있다. 하지만, 이런 명령어를 실행하면 .gitconfig에도 그대로 기록이 된다.

위에서 언급한 예시를 보면 알 수 있겠듯이, 앞에 dot(.)이 붙어있는 설정파일이라면 dotfiles라고 할 수 있겠다. dotfiles 리포지토리를 만들어서 관리를 하는 이유는 무엇인가? 그것은 바로 어떤 환경에서든 .zshrc/.gitignore 파일 같은 것들을 동일하게 사용하여 작업의 흐름을 온전히 유지할 수 있다는 장점이 있기 때문이다. dotfiles를 git과 같은 버전관리 도구로 관리할 수 있고, github 같은 저장소에 올려놓을 수 있다면.... 어떤 개발환경으로 갈아타더라도 github에서 바로 내려받고, 각 설정파일들을 옮기면 그만이기 때문에 개발환경 설정하는데 드는 시간적 비용을 굉장히 아낄 수 있다.

dotfiles를 관리하는 방법들은 여러가지 있겠지만(symbolic link를 이용한다던가 등등), 개인적으로는 chezmoi를 권장하는 바이다. chezmoi는 dotfiles들을 버전관리할 수 있게 편의성을 제공해주는 CLI 도구이다.

  • 나도 chezmoi를 엄청 애용하고 있기 때문에, 내 dotfiles를 실제로 사용해보고 싶다면, chezmoi init https://github.com/malkoG/dotfiles.git 명령을 실행해보면 된다.

다시, 본론으로 Wezterm에 대해서 알아보자.

Wezterm은 Konsole/iTerm2/Gnome Terminal/Alacritty과 같은 터미널 에뮬레이터이며, Rust 기반으로 구축이 되어 있고, GPU 가속을 지원한다. 따라서, 렌더링 자체도 어느 정도는 빠른 편이다.

주변 사람들에게 한번 써보도록 권장하는 터미널 에뮬레이터가 세 가지 정도 있는데, Alacritty/Kitty 그리고 이 글에서 소개하는 Wezterm 정도 된다. 요즘은 Zig 기반으로 만들어진 Ghostty[1]도 추천할만 한 것 같다. 하지만, 이 글에서는 Wezterm을 소개하기로 했기 때문에, Wezterm 중심으로 소개하도록 하겠다.

Wezterm은 다음과 같은 특징을 가진다.

  • Linux, MacOS, 윈도우즈, FreeBSD 다양한 환경에서 돌아간다.
  • 한 윈도우를 여러개의 pane으로 쪼개서 분할하여 멀티플렉싱을 지원한다.(물론, 나는 ZelliJ/Tmux를 쓰기때문에 잘 이용하지는 않는 기능이다.
  • 마우스 지원이 잘 된다
  • 터미널에 표시되는 글자를 캡쳐해서 하이퍼링크로 치환이 가능하다.
    • 이건 나도 잘 이용하지는 않는 기능이지만.. T0010 같은 코드가 화면 상에 보여진다면, 특정 린터 페이지의 설명화면으로 이동하는 링크를 심을 수 있다. kiyoon님의 dotfiles 참고
  • lua로 스크립팅이 가능한데, 활용할 수 있는 방향이 굉장히 다양하다.
    • 여기에서 설명한 기능들을 최대한 활용하여 스크립팅이 가능하다.
    • API 문서를 슥 훑어보았을때, "어? 설마 이게 되나?" 싶은 생각이 든다면, 여러분이 생각하는 것도 아마 가능할지도 모른다.

Wezterm, 써보자.

Wezterm을 설치한다면 설치 안내 페이지를 참고해서 설치하면 되는데, 여러분이 Wezterm을 설치했다면 당장은 검은 화면만 뜰지도 모른다.

Wezterm을 설치하고 나서, .config/wezterm/wezterm.lua 파일을 수정해야 하는데, 당장은 아래처럼 비어있을 것이다. 파일이 없다면 만들어두는 것이 좋다.

return {}

위의 코드에서 {}는 lua에서는 테이블(다른 언어로 치면, 딕셔너리/오브젝트 같은 것)이지만, wezterm 터미널의 configuration을 나타내는 테이블이다. 여기에 몇가지 추가사항을 넣어보겠다.

터미널 에뮬레이터를 설치했는데, 터미널 에뮬레이터를 설치했으면 가장 처음부터 하는게 무엇이겠는가? 바로, 폰트를 세팅하는 것이다. 터미널 환경에서 작업할때 폰트만큼 중요한게 또 없다.

local wezterm = require("wezterm")

return {
	font = wezterm.font_with_fallback({'Cascadia Code NF', 'NanumBarunGothic'}),
	font_size = 12.0,
	line_height = 1.2,
}

폰트를 가져다 쓸때는 위의 예시와 같이 font_with_fallback 함수를 이용해서 가져다 쓸 수 있고, 그 외에도 폰트 크기를 지정하거나 행간을 지정할 수도 있다. 공식페이지에서 보았듯이, 여러분의 취향에 따라 배경색 혹은 배경이미지도 지정할 수 있는데 여러분 나름대로의 기준이 있고 욕심이 난다면 한번 도전해보는 것도 나쁘지 않을 것 같다.

위의 코드를 복사 붙여넣고 편집하다보면 느낄 수 있겠지만, wezterm은 설정파일을 편집할때 Hot Reloading을 지원한다. 이 또한, 내가 가장 애정하는 기능 중 하나이다. 혹여나 wezterm 설정 파일을 수정했을때, 문법에 오류가 있거나 설정값을 잘못 지정했을 때, 새 창으로 어떤 부분에 오류가 있는지 친절하게 Alert도 띄워준다.

API 레퍼런스를 보기만 해도 스크립팅으로 기능을 확장할 수 있는 가능성이야 당연히 많긴 하겠지만, 처음 접하는 입장에서는 어떻게 커스터마이징할 지 파악하기 난해할 수 있다.

아래에서는 내가 어떻게 Wezterm을 커스터마이징을 하고 있는지 예시를 나열하는 것으로 글을 끝내겠다. Wezterm, 믿고 써보시라.

내가 Wezterm을 응용하는 방법

1. 반투명도 조정하기

Wezterm에서 터미널 색상을 설정할때, 배경색상의 반투명도를 지정할 수 있는 옵션이 있다. 나는 여기서 단축키를 입력했을때 반투명도를 동적으로 조절하고 싶었다.

반투명도를 상수로 둘 수는 있지만, 모니터 하나 짜리의 환경에서 작업한다면 브라우저를 뒤쪽에 두고 터미널 앱을 앞에 두는 식으로 작업을 많이 하게 된다. HMR(Hot Module Reloading)이 되는 개발환경이라면, 소스코드를 편집하고 화면에 즉각적으로 반영이 되는걸 기대할텐데 이걸 탭 스위칭하면서 확인하기는 굉장히 번거롭다. 온전히 작업을 유지하다가 잠깐 확인하고 싶을때 반투명도를 변경하면 되는데도 말이다.

Wezterm에서는 이벤트를 발신할 수 있고, 다른 프로세스에서 특정 이벤트를 수신했을때 어떤 동작을 할 것인지를 정의할 수 있다. Wezterm 터미널 옵션을 수정하는것도 여기에 포함될 수 있다. 특정 단축키를 입력하면, 어떤 이벤트를 발생시킬 수 있고, 그 이벤트로 인해서 화면의 반투명도를 조정할 수 있게 했다.

local default_opacity = 0.9

local keymaps = {}

-- SHIFT + CTRL + Z 키를 누르면 반투명도를 감소시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = "Z",
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'decrease-opacity',
  }
)

-- SHIFT + CTRL + X 키를 누르면 반투명도를 증가시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = 'X',
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'increase-opacity',
  }
)


-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('increase-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity
  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity + 0.1
  if opacity > 1.0 then
	opacity = 1.0
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('decrease-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity

  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity - 0.1
  if opacity < 0.3 then
	opacity = 0.3
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

return {
  keys = keymaps
}

2. 탭 이름 변경하기

대부분 터미널 에뮬레이터에서 탭 이름을 표시할때, 현재 탭에서 돌고 있는 프로세스의 이름을 명시할때가 많다. 그런데, 탭에 명시되어 있는 타이틀만 가지고는 각각의 탭이 어떤 역할을 하는 것인지 파악하기 어렵다. 어느 쪽이 서버를 띄우고 있는건지, 어느 쪽이 에디터 편집 화면인지, 어느 쪽이 LLM Agent를 돌리고 있는지 난해하다.

하지만, 아래처럼 wezterm.action.PromptInputLine API를 사용해서 프롬프트 입력을 받은 내용을 기반으로, 현재 활성화된 탭의 이름을 변경하는 식으로 인지부하를 줄일 수 있다.

local wezterm = require('wezterm')
local keymaps = {}

table.insert(
  keymaps,
  {
	key = '`',
	mods = 'CTRL',
	action = wezterm.action.PromptInputLine {
	  description = "Enter new name for tab",
	  action = wezterm.action_callback(function(window, _, line)
	    if line then
		  window:active_tab():set_title(line)
		end
	  end)
	}
  }
)

return {
  keys = keymaps
}

3. BEEP음 대신 화면이 번쩍이게 하기

Aider나 Claude Code 같은 LLM 에이전트가 작업을 수행 후 아예 작업이 끝났거나, 혹은 작업에 대한 승인을 요구할 때가 간혹 있다. LLM 에이전트가 작업을 수행하는걸 가만히 보고만 있을 순 없을 것이다.

Claude Code/Aider는 다행히도 응답을 하고 나서 추가적인 명령을 실행할 수 있는 옵션[2]을 제공해주는데, 거기에 간단하게 echo -ne '\007' 명령어를 넘겨줄 수 있다. 이 명령어는 엄청 어렵지는 않다. 터미널 앱에 내장된 시스템 벨 소리를 재생하는 명령어다.

작업 환경이 어디냐에 따라 다를 순 있겠지만, 작업 완료 여부를 음성으로 받기에는 물리적인 제약이 있을 수 있다. 아예 알림 센터를 이용한다고 치자. 업무 시간대에 방해금지 모드를 설정했다면 알림이 울리게 설정이 했더라도 시스템 제약상 묻힐 가능성도 있다.[3]

visual_bell 옵션을 활용하면, 터미널에 내장된 시스템 벨 소리를 울리는 대신 화면이 반짝이게 해서 다른 에이전트가 응답을 완료했다고 명시적으로 알림을 받을 수 있다. LLM 에이전트가 하는 일을 일일이 모니터링하지 않더라도, 다른 작업을 수행하는 중에 화면이 반짝이면 그때 확인하기만 하면 그만이다.

return {
	colors = {
		visual_bell = '#003355',
	},

	visual_bell = {
		fade_in_duration_ms  = 75,
		fade_out_duration_ms = 75,
		target               = 'BackgroundColor', -- 또는 'CursorColor'
	}
}

  1. Hashicorp 공동창업자인 Mitchell Hashimoto가 만든 터미널 에뮬레이터인데, OpenAI에서 Codex 시연할때 Ghostty 터미널로 시연한 바가 있다. ↩︎

  2. Aider는 notifications-command, Claude Code는 Hook이 있다 ↩︎

  3. 어떤 사람은 휴대전화를 진동모드로 해놓고, 텔레그램/디스코드로 알림쏴서 알림을 수신받는 방식을 쓰고 있는 것을 관찰한 바는 있다. ↩︎

Jaeyeol Lee's avatar
Jaeyeol Lee

@kodingwarrior@hackers.pub

이 글(그리고 후속작이 될 글들)은, 내 개발환경에서 자주 사용하고 있고 실제로도 애정하고 있는 도구에 대해서 소개하게 될 것 같다. 내가 어떤 환경에서 개발하고 있는지 궁금한 분들은 내 dotfiles 리포지토리를 참고해도 좋을 것 같다.

먼저, dotfiles란 무엇인가?

dotfiles라는 이름 자체만 보면 뭔가 대단해보일 것 같지만, dotfiles라는 이름 자체는 그냥 단순하다.

  • 어딘가의 가이드라인에서 지시하는대로 개발환경을 세팅하다보면, .zshrc/.bashrc 같은 것들을 마주하게 될 것이다.
  • git을 사용하고 있는 사람이라면, 어떤 diff 도구(delta, difft)를 사용할지, 어떤 alias 명령어를 등록할지 같은 것들을 명시하기 위해서 .gitconfig 같은 파일을 수정하게 될 때가 있다.
    • 물론, 이런것보다는 git config pull.rebase true 같은 명령어를 실행하는 경우가 더 많을 수 있다. 하지만, 이런 명령어를 실행하면 .gitconfig에도 그대로 기록이 된다.

위에서 언급한 예시를 보면 알 수 있겠듯이, 앞에 dot(.)이 붙어있는 설정파일이라면 dotfiles라고 할 수 있겠다. dotfiles 리포지토리를 만들어서 관리를 하는 이유는 무엇인가? 그것은 바로 어떤 환경에서든 .zshrc/.gitignore 파일 같은 것들을 동일하게 사용하여 작업의 흐름을 온전히 유지할 수 있다는 장점이 있기 때문이다. dotfiles를 git과 같은 버전관리 도구로 관리할 수 있고, github 같은 저장소에 올려놓을 수 있다면.... 어떤 개발환경으로 갈아타더라도 github에서 바로 내려받고, 각 설정파일들을 옮기면 그만이기 때문에 개발환경 설정하는데 드는 시간적 비용을 굉장히 아낄 수 있다.

dotfiles를 관리하는 방법들은 여러가지 있겠지만(symbolic link를 이용한다던가 등등), 개인적으로는 chezmoi를 권장하는 바이다. chezmoi는 dotfiles들을 버전관리할 수 있게 편의성을 제공해주는 CLI 도구이다.

  • 나도 chezmoi를 엄청 애용하고 있기 때문에, 내 dotfiles를 실제로 사용해보고 싶다면, chezmoi init https://github.com/malkoG/dotfiles.git 명령을 실행해보면 된다.

다시, 본론으로 Wezterm에 대해서 알아보자.

Wezterm은 Konsole/iTerm2/Gnome Terminal/Alacritty과 같은 터미널 에뮬레이터이며, Rust 기반으로 구축이 되어 있고, GPU 가속을 지원한다. 따라서, 렌더링 자체도 어느 정도는 빠른 편이다.

주변 사람들에게 한번 써보도록 권장하는 터미널 에뮬레이터가 세 가지 정도 있는데, Alacritty/Kitty 그리고 이 글에서 소개하는 Wezterm 정도 된다. 요즘은 Zig 기반으로 만들어진 Ghostty[1]도 추천할만 한 것 같다. 하지만, 이 글에서는 Wezterm을 소개하기로 했기 때문에, Wezterm 중심으로 소개하도록 하겠다.

Wezterm은 다음과 같은 특징을 가진다.

  • Linux, MacOS, 윈도우즈, FreeBSD 다양한 환경에서 돌아간다.
  • 한 윈도우를 여러개의 pane으로 쪼개서 분할하여 멀티플렉싱을 지원한다.(물론, 나는 ZelliJ/Tmux를 쓰기때문에 잘 이용하지는 않는 기능이다.
  • 마우스 지원이 잘 된다
  • 터미널에 표시되는 글자를 캡쳐해서 하이퍼링크로 치환이 가능하다.
    • 이건 나도 잘 이용하지는 않는 기능이지만.. T0010 같은 코드가 화면 상에 보여진다면, 특정 린터 페이지의 설명화면으로 이동하는 링크를 심을 수 있다. kiyoon님의 dotfiles 참고
  • lua로 스크립팅이 가능한데, 활용할 수 있는 방향이 굉장히 다양하다.
    • 여기에서 설명한 기능들을 최대한 활용하여 스크립팅이 가능하다.
    • API 문서를 슥 훑어보았을때, "어? 설마 이게 되나?" 싶은 생각이 든다면, 여러분이 생각하는 것도 아마 가능할지도 모른다.

Wezterm, 써보자.

Wezterm을 설치한다면 설치 안내 페이지를 참고해서 설치하면 되는데, 여러분이 Wezterm을 설치했다면 당장은 검은 화면만 뜰지도 모른다.

Wezterm을 설치하고 나서, .config/wezterm/wezterm.lua 파일을 수정해야 하는데, 당장은 아래처럼 비어있을 것이다. 파일이 없다면 만들어두는 것이 좋다.

return {}

위의 코드에서 {}는 lua에서는 테이블(다른 언어로 치면, 딕셔너리/오브젝트 같은 것)이지만, wezterm 터미널의 configuration을 나타내는 테이블이다. 여기에 몇가지 추가사항을 넣어보겠다.

터미널 에뮬레이터를 설치했는데, 터미널 에뮬레이터를 설치했으면 가장 처음부터 하는게 무엇이겠는가? 바로, 폰트를 세팅하는 것이다. 터미널 환경에서 작업할때 폰트만큼 중요한게 또 없다.

local wezterm = require("wezterm")

return {
	font = wezterm.font_with_fallback({'Cascadia Code NF', 'NanumBarunGothic'}),
	font_size = 12.0,
	line_height = 1.2,
}

폰트를 가져다 쓸때는 위의 예시와 같이 font_with_fallback 함수를 이용해서 가져다 쓸 수 있고, 그 외에도 폰트 크기를 지정하거나 행간을 지정할 수도 있다. 공식페이지에서 보았듯이, 여러분의 취향에 따라 배경색 혹은 배경이미지도 지정할 수 있는데 여러분 나름대로의 기준이 있고 욕심이 난다면 한번 도전해보는 것도 나쁘지 않을 것 같다.

위의 코드를 복사 붙여넣고 편집하다보면 느낄 수 있겠지만, wezterm은 설정파일을 편집할때 Hot Reloading을 지원한다. 이 또한, 내가 가장 애정하는 기능 중 하나이다. 혹여나 wezterm 설정 파일을 수정했을때, 문법에 오류가 있거나 설정값을 잘못 지정했을 때, 새 창으로 어떤 부분에 오류가 있는지 친절하게 Alert도 띄워준다.

API 레퍼런스를 보기만 해도 스크립팅으로 기능을 확장할 수 있는 가능성이야 당연히 많긴 하겠지만, 처음 접하는 입장에서는 어떻게 커스터마이징할 지 파악하기 난해할 수 있다.

아래에서는 내가 어떻게 Wezterm을 커스터마이징을 하고 있는지 예시를 나열하는 것으로 글을 끝내겠다. Wezterm, 믿고 써보시라.

내가 Wezterm을 응용하는 방법

1. 반투명도 조정하기

Wezterm에서 터미널 색상을 설정할때, 배경색상의 반투명도를 지정할 수 있는 옵션이 있다. 나는 여기서 단축키를 입력했을때 반투명도를 동적으로 조절하고 싶었다.

반투명도를 상수로 둘 수는 있지만, 모니터 하나 짜리의 환경에서 작업한다면 브라우저를 뒤쪽에 두고 터미널 앱을 앞에 두는 식으로 작업을 많이 하게 된다. HMR(Hot Module Reloading)이 되는 개발환경이라면, 소스코드를 편집하고 화면에 즉각적으로 반영이 되는걸 기대할텐데 이걸 탭 스위칭하면서 확인하기는 굉장히 번거롭다. 온전히 작업을 유지하다가 잠깐 확인하고 싶을때 반투명도를 변경하면 되는데도 말이다.

Wezterm에서는 이벤트를 발신할 수 있고, 다른 프로세스에서 특정 이벤트를 수신했을때 어떤 동작을 할 것인지를 정의할 수 있다. Wezterm 터미널 옵션을 수정하는것도 여기에 포함될 수 있다. 특정 단축키를 입력하면, 어떤 이벤트를 발생시킬 수 있고, 그 이벤트로 인해서 화면의 반투명도를 조정할 수 있게 했다.

local default_opacity = 0.9

local keymaps = {}

-- SHIFT + CTRL + Z 키를 누르면 반투명도를 감소시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = "Z",
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'decrease-opacity',
  }
)

-- SHIFT + CTRL + X 키를 누르면 반투명도를 증가시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = 'X',
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'increase-opacity',
  }
)


-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('increase-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity
  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity + 0.1
  if opacity > 1.0 then
	opacity = 1.0
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('decrease-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity

  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity - 0.1
  if opacity < 0.3 then
	opacity = 0.3
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

return {
  keys = keymaps
}

2. 탭 이름 변경하기

대부분 터미널 에뮬레이터에서 탭 이름을 표시할때, 현재 탭에서 돌고 있는 프로세스의 이름을 명시할때가 많다. 그런데, 탭에 명시되어 있는 타이틀만 가지고는 각각의 탭이 어떤 역할을 하는 것인지 파악하기 어렵다. 어느 쪽이 서버를 띄우고 있는건지, 어느 쪽이 에디터 편집 화면인지, 어느 쪽이 LLM Agent를 돌리고 있는지 난해하다.

하지만, 아래처럼 wezterm.action.PromptInputLine API를 사용해서 프롬프트 입력을 받은 내용을 기반으로, 현재 활성화된 탭의 이름을 변경하는 식으로 인지부하를 줄일 수 있다.

local wezterm = require('wezterm')
local keymaps = {}

table.insert(
  keymaps,
  {
	key = '`',
	mods = 'CTRL',
	action = wezterm.action.PromptInputLine {
	  description = "Enter new name for tab",
	  action = wezterm.action_callback(function(window, _, line)
	    if line then
		  window:active_tab():set_title(line)
		end
	  end)
	}
  }
)

return {
  keys = keymaps
}

3. BEEP음 대신 화면이 번쩍이게 하기

Aider나 Claude Code 같은 LLM 에이전트가 작업을 수행 후 아예 작업이 끝났거나, 혹은 작업에 대한 승인을 요구할 때가 간혹 있다. LLM 에이전트가 작업을 수행하는걸 가만히 보고만 있을 순 없을 것이다.

Claude Code/Aider는 다행히도 응답을 하고 나서 추가적인 명령을 실행할 수 있는 옵션[2]을 제공해주는데, 거기에 간단하게 echo -ne '\007' 명령어를 넘겨줄 수 있다. 이 명령어는 엄청 어렵지는 않다. 터미널 앱에 내장된 시스템 벨 소리를 재생하는 명령어다.

작업 환경이 어디냐에 따라 다를 순 있겠지만, 작업 완료 여부를 음성으로 받기에는 물리적인 제약이 있을 수 있다. 아예 알림 센터를 이용한다고 치자. 업무 시간대에 방해금지 모드를 설정했다면 알림이 울리게 설정이 했더라도 시스템 제약상 묻힐 가능성도 있다.[3]

visual_bell 옵션을 활용하면, 터미널에 내장된 시스템 벨 소리를 울리는 대신 화면이 반짝이게 해서 다른 에이전트가 응답을 완료했다고 명시적으로 알림을 받을 수 있다. LLM 에이전트가 하는 일을 일일이 모니터링하지 않더라도, 다른 작업을 수행하는 중에 화면이 반짝이면 그때 확인하기만 하면 그만이다.

return {
	colors = {
		visual_bell = '#003355',
	},

	visual_bell = {
		fade_in_duration_ms  = 75,
		fade_out_duration_ms = 75,
		target               = 'BackgroundColor', -- 또는 'CursorColor'
	}
}

  1. Hashicorp 공동창업자인 Mitchell Hashimoto가 만든 터미널 에뮬레이터인데, OpenAI에서 Codex 시연할때 Ghostty 터미널로 시연한 바가 있다. ↩︎

  2. Aider는 notifications-command, Claude Code는 Hook이 있다 ↩︎

  3. 어떤 사람은 휴대전화를 진동모드로 해놓고, 텔레그램/디스코드로 알림쏴서 알림을 수신받는 방식을 쓰고 있는 것을 관찰한 바는 있다. ↩︎

Jaeyeol Lee's avatar
Jaeyeol Lee

@kodingwarrior@hackers.pub

이 글(그리고 후속작이 될 글들)은, 내 개발환경에서 자주 사용하고 있고 실제로도 애정하고 있는 도구에 대해서 소개하게 될 것 같다. 내가 어떤 환경에서 개발하고 있는지 궁금한 분들은 내 dotfiles 리포지토리를 참고해도 좋을 것 같다.

먼저, dotfiles란 무엇인가?

dotfiles라는 이름 자체만 보면 뭔가 대단해보일 것 같지만, dotfiles라는 이름 자체는 그냥 단순하다.

  • 어딘가의 가이드라인에서 지시하는대로 개발환경을 세팅하다보면, .zshrc/.bashrc 같은 것들을 마주하게 될 것이다.
  • git을 사용하고 있는 사람이라면, 어떤 diff 도구(delta, difft)를 사용할지, 어떤 alias 명령어를 등록할지 같은 것들을 명시하기 위해서 .gitconfig 같은 파일을 수정하게 될 때가 있다.
    • 물론, 이런것보다는 git config pull.rebase true 같은 명령어를 실행하는 경우가 더 많을 수 있다. 하지만, 이런 명령어를 실행하면 .gitconfig에도 그대로 기록이 된다.

위에서 언급한 예시를 보면 알 수 있겠듯이, 앞에 dot(.)이 붙어있는 설정파일이라면 dotfiles라고 할 수 있겠다. dotfiles 리포지토리를 만들어서 관리를 하는 이유는 무엇인가? 그것은 바로 어떤 환경에서든 .zshrc/.gitignore 파일 같은 것들을 동일하게 사용하여 작업의 흐름을 온전히 유지할 수 있다는 장점이 있기 때문이다. dotfiles를 git과 같은 버전관리 도구로 관리할 수 있고, github 같은 저장소에 올려놓을 수 있다면.... 어떤 개발환경으로 갈아타더라도 github에서 바로 내려받고, 각 설정파일들을 옮기면 그만이기 때문에 개발환경 설정하는데 드는 시간적 비용을 굉장히 아낄 수 있다.

dotfiles를 관리하는 방법들은 여러가지 있겠지만(symbolic link를 이용한다던가 등등), 개인적으로는 chezmoi를 권장하는 바이다. chezmoi는 dotfiles들을 버전관리할 수 있게 편의성을 제공해주는 CLI 도구이다.

  • 나도 chezmoi를 엄청 애용하고 있기 때문에, 내 dotfiles를 실제로 사용해보고 싶다면, chezmoi init https://github.com/malkoG/dotfiles.git 명령을 실행해보면 된다.

다시, 본론으로 Wezterm에 대해서 알아보자.

Wezterm은 Konsole/iTerm2/Gnome Terminal/Alacritty과 같은 터미널 에뮬레이터이며, Rust 기반으로 구축이 되어 있고, GPU 가속을 지원한다. 따라서, 렌더링 자체도 어느 정도는 빠른 편이다.

주변 사람들에게 한번 써보도록 권장하는 터미널 에뮬레이터가 세 가지 정도 있는데, Alacritty/Kitty 그리고 이 글에서 소개하는 Wezterm 정도 된다. 요즘은 Zig 기반으로 만들어진 Ghostty[1]도 추천할만 한 것 같다. 하지만, 이 글에서는 Wezterm을 소개하기로 했기 때문에, Wezterm 중심으로 소개하도록 하겠다.

Wezterm은 다음과 같은 특징을 가진다.

  • Linux, MacOS, 윈도우즈, FreeBSD 다양한 환경에서 돌아간다.
  • 한 윈도우를 여러개의 pane으로 쪼개서 분할하여 멀티플렉싱을 지원한다.(물론, 나는 ZelliJ/Tmux를 쓰기때문에 잘 이용하지는 않는 기능이다.
  • 마우스 지원이 잘 된다
  • 터미널에 표시되는 글자를 캡쳐해서 하이퍼링크로 치환이 가능하다.
    • 이건 나도 잘 이용하지는 않는 기능이지만.. T0010 같은 코드가 화면 상에 보여진다면, 특정 린터 페이지의 설명화면으로 이동하는 링크를 심을 수 있다. kiyoon님의 dotfiles 참고
  • lua로 스크립팅이 가능한데, 활용할 수 있는 방향이 굉장히 다양하다.
    • 여기에서 설명한 기능들을 최대한 활용하여 스크립팅이 가능하다.
    • API 문서를 슥 훑어보았을때, "어? 설마 이게 되나?" 싶은 생각이 든다면, 여러분이 생각하는 것도 아마 가능할지도 모른다.

Wezterm, 써보자.

Wezterm을 설치한다면 설치 안내 페이지를 참고해서 설치하면 되는데, 여러분이 Wezterm을 설치했다면 당장은 검은 화면만 뜰지도 모른다.

Wezterm을 설치하고 나서, .config/wezterm/wezterm.lua 파일을 수정해야 하는데, 당장은 아래처럼 비어있을 것이다. 파일이 없다면 만들어두는 것이 좋다.

return {}

위의 코드에서 {}는 lua에서는 테이블(다른 언어로 치면, 딕셔너리/오브젝트 같은 것)이지만, wezterm 터미널의 configuration을 나타내는 테이블이다. 여기에 몇가지 추가사항을 넣어보겠다.

터미널 에뮬레이터를 설치했는데, 터미널 에뮬레이터를 설치했으면 가장 처음부터 하는게 무엇이겠는가? 바로, 폰트를 세팅하는 것이다. 터미널 환경에서 작업할때 폰트만큼 중요한게 또 없다.

local wezterm = require("wezterm")

return {
	font = wezterm.font_with_fallback({'Cascadia Code NF', 'NanumBarunGothic'}),
	font_size = 12.0,
	line_height = 1.2,
}

폰트를 가져다 쓸때는 위의 예시와 같이 font_with_fallback 함수를 이용해서 가져다 쓸 수 있고, 그 외에도 폰트 크기를 지정하거나 행간을 지정할 수도 있다. 공식페이지에서 보았듯이, 여러분의 취향에 따라 배경색 혹은 배경이미지도 지정할 수 있는데 여러분 나름대로의 기준이 있고 욕심이 난다면 한번 도전해보는 것도 나쁘지 않을 것 같다.

위의 코드를 복사 붙여넣고 편집하다보면 느낄 수 있겠지만, wezterm은 설정파일을 편집할때 Hot Reloading을 지원한다. 이 또한, 내가 가장 애정하는 기능 중 하나이다. 혹여나 wezterm 설정 파일을 수정했을때, 문법에 오류가 있거나 설정값을 잘못 지정했을 때, 새 창으로 어떤 부분에 오류가 있는지 친절하게 Alert도 띄워준다.

API 레퍼런스를 보기만 해도 스크립팅으로 기능을 확장할 수 있는 가능성이야 당연히 많긴 하겠지만, 처음 접하는 입장에서는 어떻게 커스터마이징할 지 파악하기 난해할 수 있다.

아래에서는 내가 어떻게 Wezterm을 커스터마이징을 하고 있는지 예시를 나열하는 것으로 글을 끝내겠다. Wezterm, 믿고 써보시라.

내가 Wezterm을 응용하는 방법

1. 반투명도 조정하기

Wezterm에서 터미널 색상을 설정할때, 배경색상의 반투명도를 지정할 수 있는 옵션이 있다. 나는 여기서 단축키를 입력했을때 반투명도를 동적으로 조절하고 싶었다.

반투명도를 상수로 둘 수는 있지만, 모니터 하나 짜리의 환경에서 작업한다면 브라우저를 뒤쪽에 두고 터미널 앱을 앞에 두는 식으로 작업을 많이 하게 된다. HMR(Hot Module Reloading)이 되는 개발환경이라면, 소스코드를 편집하고 화면에 즉각적으로 반영이 되는걸 기대할텐데 이걸 탭 스위칭하면서 확인하기는 굉장히 번거롭다. 온전히 작업을 유지하다가 잠깐 확인하고 싶을때 반투명도를 변경하면 되는데도 말이다.

Wezterm에서는 이벤트를 발신할 수 있고, 다른 프로세스에서 특정 이벤트를 수신했을때 어떤 동작을 할 것인지를 정의할 수 있다. Wezterm 터미널 옵션을 수정하는것도 여기에 포함될 수 있다. 특정 단축키를 입력하면, 어떤 이벤트를 발생시킬 수 있고, 그 이벤트로 인해서 화면의 반투명도를 조정할 수 있게 했다.

local default_opacity = 0.9

local keymaps = {}

-- SHIFT + CTRL + Z 키를 누르면 반투명도를 감소시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = "Z",
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'decrease-opacity',
  }
)

-- SHIFT + CTRL + X 키를 누르면 반투명도를 증가시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = 'X',
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'increase-opacity',
  }
)


-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('increase-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity
  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity + 0.1
  if opacity > 1.0 then
	opacity = 1.0
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('decrease-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity

  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity - 0.1
  if opacity < 0.3 then
	opacity = 0.3
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

return {
  keys = keymaps
}

2. 탭 이름 변경하기

대부분 터미널 에뮬레이터에서 탭 이름을 표시할때, 현재 탭에서 돌고 있는 프로세스의 이름을 명시할때가 많다. 그런데, 탭에 명시되어 있는 타이틀만 가지고는 각각의 탭이 어떤 역할을 하는 것인지 파악하기 어렵다. 어느 쪽이 서버를 띄우고 있는건지, 어느 쪽이 에디터 편집 화면인지, 어느 쪽이 LLM Agent를 돌리고 있는지 난해하다.

하지만, 아래처럼 wezterm.action.PromptInputLine API를 사용해서 프롬프트 입력을 받은 내용을 기반으로, 현재 활성화된 탭의 이름을 변경하는 식으로 인지부하를 줄일 수 있다.

local wezterm = require('wezterm')
local keymaps = {}

table.insert(
  keymaps,
  {
	key = '`',
	mods = 'CTRL',
	action = wezterm.action.PromptInputLine {
	  description = "Enter new name for tab",
	  action = wezterm.action_callback(function(window, _, line)
	    if line then
		  window:active_tab():set_title(line)
		end
	  end)
	}
  }
)

return {
  keys = keymaps
}

3. BEEP음 대신 화면이 번쩍이게 하기

Aider나 Claude Code 같은 LLM 에이전트가 작업을 수행 후 아예 작업이 끝났거나, 혹은 작업에 대한 승인을 요구할 때가 간혹 있다. LLM 에이전트가 작업을 수행하는걸 가만히 보고만 있을 순 없을 것이다.

Claude Code/Aider는 다행히도 응답을 하고 나서 추가적인 명령을 실행할 수 있는 옵션[2]을 제공해주는데, 거기에 간단하게 echo -ne '\007' 명령어를 넘겨줄 수 있다. 이 명령어는 엄청 어렵지는 않다. 터미널 앱에 내장된 시스템 벨 소리를 재생하는 명령어다.

작업 환경이 어디냐에 따라 다를 순 있겠지만, 작업 완료 여부를 음성으로 받기에는 물리적인 제약이 있을 수 있다. 아예 알림 센터를 이용한다고 치자. 업무 시간대에 방해금지 모드를 설정했다면 알림이 울리게 설정이 했더라도 시스템 제약상 묻힐 가능성도 있다.[3]

visual_bell 옵션을 활용하면, 터미널에 내장된 시스템 벨 소리를 울리는 대신 화면이 반짝이게 해서 다른 에이전트가 응답을 완료했다고 명시적으로 알림을 받을 수 있다. LLM 에이전트가 하는 일을 일일이 모니터링하지 않더라도, 다른 작업을 수행하는 중에 화면이 반짝이면 그때 확인하기만 하면 그만이다.

return {
	colors = {
		visual_bell = '#003355',
	},

	visual_bell = {
		fade_in_duration_ms  = 75,
		fade_out_duration_ms = 75,
		target               = 'BackgroundColor', -- 또는 'CursorColor'
	}
}

  1. Hashicorp 공동창업자인 Mitchell Hashimoto가 만든 터미널 에뮬레이터인데, OpenAI에서 Codex 시연할때 Ghostty 터미널로 시연한 바가 있다. ↩︎

  2. Aider는 notifications-command, Claude Code는 Hook이 있다 ↩︎

  3. 어떤 사람은 휴대전화를 진동모드로 해놓고, 텔레그램/디스코드로 알림쏴서 알림을 수신받는 방식을 쓰고 있는 것을 관찰한 바는 있다. ↩︎

Jaeyeol Lee's avatar
Jaeyeol Lee

@kodingwarrior@hackers.pub

이 글(그리고 후속작이 될 글들)은, 내 개발환경에서 자주 사용하고 있고 실제로도 애정하고 있는 도구에 대해서 소개하게 될 것 같다. 내가 어떤 환경에서 개발하고 있는지 궁금한 분들은 내 dotfiles 리포지토리를 참고해도 좋을 것 같다.

먼저, dotfiles란 무엇인가?

dotfiles라는 이름 자체만 보면 뭔가 대단해보일 것 같지만, dotfiles라는 이름 자체는 그냥 단순하다.

  • 어딘가의 가이드라인에서 지시하는대로 개발환경을 세팅하다보면, .zshrc/.bashrc 같은 것들을 마주하게 될 것이다.
  • git을 사용하고 있는 사람이라면, 어떤 diff 도구(delta, difft)를 사용할지, 어떤 alias 명령어를 등록할지 같은 것들을 명시하기 위해서 .gitconfig 같은 파일을 수정하게 될 때가 있다.
    • 물론, 이런것보다는 git config pull.rebase true 같은 명령어를 실행하는 경우가 더 많을 수 있다. 하지만, 이런 명령어를 실행하면 .gitconfig에도 그대로 기록이 된다.

위에서 언급한 예시를 보면 알 수 있겠듯이, 앞에 dot(.)이 붙어있는 설정파일이라면 dotfiles라고 할 수 있겠다. dotfiles 리포지토리를 만들어서 관리를 하는 이유는 무엇인가? 그것은 바로 어떤 환경에서든 .zshrc/.gitignore 파일 같은 것들을 동일하게 사용하여 작업의 흐름을 온전히 유지할 수 있다는 장점이 있기 때문이다. dotfiles를 git과 같은 버전관리 도구로 관리할 수 있고, github 같은 저장소에 올려놓을 수 있다면.... 어떤 개발환경으로 갈아타더라도 github에서 바로 내려받고, 각 설정파일들을 옮기면 그만이기 때문에 개발환경 설정하는데 드는 시간적 비용을 굉장히 아낄 수 있다.

dotfiles를 관리하는 방법들은 여러가지 있겠지만(symbolic link를 이용한다던가 등등), 개인적으로는 chezmoi를 권장하는 바이다. chezmoi는 dotfiles들을 버전관리할 수 있게 편의성을 제공해주는 CLI 도구이다.

  • 나도 chezmoi를 엄청 애용하고 있기 때문에, 내 dotfiles를 실제로 사용해보고 싶다면, chezmoi init https://github.com/malkoG/dotfiles.git 명령을 실행해보면 된다.

다시, 본론으로 Wezterm에 대해서 알아보자.

Wezterm은 Konsole/iTerm2/Gnome Terminal/Alacritty과 같은 터미널 에뮬레이터이며, Rust 기반으로 구축이 되어 있고, GPU 가속을 지원한다. 따라서, 렌더링 자체도 어느 정도는 빠른 편이다.

주변 사람들에게 한번 써보도록 권장하는 터미널 에뮬레이터가 세 가지 정도 있는데, Alacritty/Kitty 그리고 이 글에서 소개하는 Wezterm 정도 된다. 요즘은 Zig 기반으로 만들어진 Ghostty[1]도 추천할만 한 것 같다. 하지만, 이 글에서는 Wezterm을 소개하기로 했기 때문에, Wezterm 중심으로 소개하도록 하겠다.

Wezterm은 다음과 같은 특징을 가진다.

  • Linux, MacOS, 윈도우즈, FreeBSD 다양한 환경에서 돌아간다.
  • 한 윈도우를 여러개의 pane으로 쪼개서 분할하여 멀티플렉싱을 지원한다.(물론, 나는 ZelliJ/Tmux를 쓰기때문에 잘 이용하지는 않는 기능이다.
  • 마우스 지원이 잘 된다
  • 터미널에 표시되는 글자를 캡쳐해서 하이퍼링크로 치환이 가능하다.
    • 이건 나도 잘 이용하지는 않는 기능이지만.. T0010 같은 코드가 화면 상에 보여진다면, 특정 린터 페이지의 설명화면으로 이동하는 링크를 심을 수 있다. kiyoon님의 dotfiles 참고
  • lua로 스크립팅이 가능한데, 활용할 수 있는 방향이 굉장히 다양하다.
    • 여기에서 설명한 기능들을 최대한 활용하여 스크립팅이 가능하다.
    • API 문서를 슥 훑어보았을때, "어? 설마 이게 되나?" 싶은 생각이 든다면, 여러분이 생각하는 것도 아마 가능할지도 모른다.

Wezterm, 써보자.

Wezterm을 설치한다면 설치 안내 페이지를 참고해서 설치하면 되는데, 여러분이 Wezterm을 설치했다면 당장은 검은 화면만 뜰지도 모른다.

Wezterm을 설치하고 나서, .config/wezterm/wezterm.lua 파일을 수정해야 하는데, 당장은 아래처럼 비어있을 것이다. 파일이 없다면 만들어두는 것이 좋다.

return {}

위의 코드에서 {}는 lua에서는 테이블(다른 언어로 치면, 딕셔너리/오브젝트 같은 것)이지만, wezterm 터미널의 configuration을 나타내는 테이블이다. 여기에 몇가지 추가사항을 넣어보겠다.

터미널 에뮬레이터를 설치했는데, 터미널 에뮬레이터를 설치했으면 가장 처음부터 하는게 무엇이겠는가? 바로, 폰트를 세팅하는 것이다. 터미널 환경에서 작업할때 폰트만큼 중요한게 또 없다.

local wezterm = require("wezterm")

return {
	font = wezterm.font_with_fallback({'Cascadia Code NF', 'NanumBarunGothic'}),
	font_size = 12.0,
	line_height = 1.2,
}

폰트를 가져다 쓸때는 위의 예시와 같이 font_with_fallback 함수를 이용해서 가져다 쓸 수 있고, 그 외에도 폰트 크기를 지정하거나 행간을 지정할 수도 있다. 공식페이지에서 보았듯이, 여러분의 취향에 따라 배경색 혹은 배경이미지도 지정할 수 있는데 여러분 나름대로의 기준이 있고 욕심이 난다면 한번 도전해보는 것도 나쁘지 않을 것 같다.

위의 코드를 복사 붙여넣고 편집하다보면 느낄 수 있겠지만, wezterm은 설정파일을 편집할때 Hot Reloading을 지원한다. 이 또한, 내가 가장 애정하는 기능 중 하나이다. 혹여나 wezterm 설정 파일을 수정했을때, 문법에 오류가 있거나 설정값을 잘못 지정했을 때, 새 창으로 어떤 부분에 오류가 있는지 친절하게 Alert도 띄워준다.

API 레퍼런스를 보기만 해도 스크립팅으로 기능을 확장할 수 있는 가능성이야 당연히 많긴 하겠지만, 처음 접하는 입장에서는 어떻게 커스터마이징할 지 파악하기 난해할 수 있다.

아래에서는 내가 어떻게 Wezterm을 커스터마이징을 하고 있는지 예시를 나열하는 것으로 글을 끝내겠다. Wezterm, 믿고 써보시라.

내가 Wezterm을 응용하는 방법

1. 반투명도 조정하기

Wezterm에서 터미널 색상을 설정할때, 배경색상의 반투명도를 지정할 수 있는 옵션이 있다. 나는 여기서 단축키를 입력했을때 반투명도를 동적으로 조절하고 싶었다.

반투명도를 상수로 둘 수는 있지만, 모니터 하나 짜리의 환경에서 작업한다면 브라우저를 뒤쪽에 두고 터미널 앱을 앞에 두는 식으로 작업을 많이 하게 된다. HMR(Hot Module Reloading)이 되는 개발환경이라면, 소스코드를 편집하고 화면에 즉각적으로 반영이 되는걸 기대할텐데 이걸 탭 스위칭하면서 확인하기는 굉장히 번거롭다. 온전히 작업을 유지하다가 잠깐 확인하고 싶을때 반투명도를 변경하면 되는데도 말이다.

Wezterm에서는 이벤트를 발신할 수 있고, 다른 프로세스에서 특정 이벤트를 수신했을때 어떤 동작을 할 것인지를 정의할 수 있다. Wezterm 터미널 옵션을 수정하는것도 여기에 포함될 수 있다. 특정 단축키를 입력하면, 어떤 이벤트를 발생시킬 수 있고, 그 이벤트로 인해서 화면의 반투명도를 조정할 수 있게 했다.

local default_opacity = 0.9

local keymaps = {}

-- SHIFT + CTRL + Z 키를 누르면 반투명도를 감소시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = "Z",
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'decrease-opacity',
  }
)

-- SHIFT + CTRL + X 키를 누르면 반투명도를 증가시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = 'X',
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'increase-opacity',
  }
)


-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('increase-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity
  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity + 0.1
  if opacity > 1.0 then
	opacity = 1.0
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('decrease-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity

  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity - 0.1
  if opacity < 0.3 then
	opacity = 0.3
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

return {
  keys = keymaps
}

2. 탭 이름 변경하기

대부분 터미널 에뮬레이터에서 탭 이름을 표시할때, 현재 탭에서 돌고 있는 프로세스의 이름을 명시할때가 많다. 그런데, 탭에 명시되어 있는 타이틀만 가지고는 각각의 탭이 어떤 역할을 하는 것인지 파악하기 어렵다. 어느 쪽이 서버를 띄우고 있는건지, 어느 쪽이 에디터 편집 화면인지, 어느 쪽이 LLM Agent를 돌리고 있는지 난해하다.

하지만, 아래처럼 wezterm.action.PromptInputLine API를 사용해서 프롬프트 입력을 받은 내용을 기반으로, 현재 활성화된 탭의 이름을 변경하는 식으로 인지부하를 줄일 수 있다.

local wezterm = require('wezterm')
local keymaps = {}

table.insert(
  keymaps,
  {
	key = '`',
	mods = 'CTRL',
	action = wezterm.action.PromptInputLine {
	  description = "Enter new name for tab",
	  action = wezterm.action_callback(function(window, _, line)
	    if line then
		  window:active_tab():set_title(line)
		end
	  end)
	}
  }
)

return {
  keys = keymaps
}

3. BEEP음 대신 화면이 번쩍이게 하기

Aider나 Claude Code 같은 LLM 에이전트가 작업을 수행 후 아예 작업이 끝났거나, 혹은 작업에 대한 승인을 요구할 때가 간혹 있다. LLM 에이전트가 작업을 수행하는걸 가만히 보고만 있을 순 없을 것이다.

Claude Code/Aider는 다행히도 응답을 하고 나서 추가적인 명령을 실행할 수 있는 옵션[2]을 제공해주는데, 거기에 간단하게 echo -ne '\007' 명령어를 넘겨줄 수 있다. 이 명령어는 엄청 어렵지는 않다. 터미널 앱에 내장된 시스템 벨 소리를 재생하는 명령어다.

작업 환경이 어디냐에 따라 다를 순 있겠지만, 작업 완료 여부를 음성으로 받기에는 물리적인 제약이 있을 수 있다. 아예 알림 센터를 이용한다고 치자. 업무 시간대에 방해금지 모드를 설정했다면 알림이 울리게 설정이 했더라도 시스템 제약상 묻힐 가능성도 있다.[3]

visual_bell 옵션을 활용하면, 터미널에 내장된 시스템 벨 소리를 울리는 대신 화면이 반짝이게 해서 다른 에이전트가 응답을 완료했다고 명시적으로 알림을 받을 수 있다. LLM 에이전트가 하는 일을 일일이 모니터링하지 않더라도, 다른 작업을 수행하는 중에 화면이 반짝이면 그때 확인하기만 하면 그만이다.

return {
	colors = {
		visual_bell = '#003355',
	},

	visual_bell = {
		fade_in_duration_ms  = 75,
		fade_out_duration_ms = 75,
		target               = 'BackgroundColor', -- 또는 'CursorColor'
	}
}

  1. Hashicorp 공동창업자인 Mitchell Hashimoto가 만든 터미널 에뮬레이터인데, OpenAI에서 Codex 시연할때 Ghostty 터미널로 시연한 바가 있다. ↩︎

  2. Aider는 notifications-command, Claude Code는 Hook이 있다 ↩︎

  3. 어떤 사람은 휴대전화를 진동모드로 해놓고, 텔레그램/디스코드로 알림쏴서 알림을 수신받는 방식을 쓰고 있는 것을 관찰한 바는 있다. ↩︎

Jaeyeol Lee's avatar
Jaeyeol Lee

@kodingwarrior@hackers.pub

이 글(그리고 후속작이 될 글들)은, 내 개발환경에서 자주 사용하고 있고 실제로도 애정하고 있는 도구에 대해서 소개하게 될 것 같다. 내가 어떤 환경에서 개발하고 있는지 궁금한 분들은 내 dotfiles 리포지토리를 참고해도 좋을 것 같다.

먼저, dotfiles란 무엇인가?

dotfiles라는 이름 자체만 보면 뭔가 대단해보일 것 같지만, dotfiles라는 이름 자체는 그냥 단순하다.

  • 어딘가의 가이드라인에서 지시하는대로 개발환경을 세팅하다보면, .zshrc/.bashrc 같은 것들을 마주하게 될 것이다.
  • git을 사용하고 있는 사람이라면, 어떤 diff 도구(delta, difft)를 사용할지, 어떤 alias 명령어를 등록할지 같은 것들을 명시하기 위해서 .gitconfig 같은 파일을 수정하게 될 때가 있다.
    • 물론, 이런것보다는 git config pull.rebase true 같은 명령어를 실행하는 경우가 더 많을 수 있다. 하지만, 이런 명령어를 실행하면 .gitconfig에도 그대로 기록이 된다.

위에서 언급한 예시를 보면 알 수 있겠듯이, 앞에 dot(.)이 붙어있는 설정파일이라면 dotfiles라고 할 수 있겠다. dotfiles 리포지토리를 만들어서 관리를 하는 이유는 무엇인가? 그것은 바로 어떤 환경에서든 .zshrc/.gitignore 파일 같은 것들을 동일하게 사용하여 작업의 흐름을 온전히 유지할 수 있다는 장점이 있기 때문이다. dotfiles를 git과 같은 버전관리 도구로 관리할 수 있고, github 같은 저장소에 올려놓을 수 있다면.... 어떤 개발환경으로 갈아타더라도 github에서 바로 내려받고, 각 설정파일들을 옮기면 그만이기 때문에 개발환경 설정하는데 드는 시간적 비용을 굉장히 아낄 수 있다.

dotfiles를 관리하는 방법들은 여러가지 있겠지만(symbolic link를 이용한다던가 등등), 개인적으로는 chezmoi를 권장하는 바이다. chezmoi는 dotfiles들을 버전관리할 수 있게 편의성을 제공해주는 CLI 도구이다.

  • 나도 chezmoi를 엄청 애용하고 있기 때문에, 내 dotfiles를 실제로 사용해보고 싶다면, chezmoi init https://github.com/malkoG/dotfiles.git 명령을 실행해보면 된다.

다시, 본론으로 Wezterm에 대해서 알아보자.

Wezterm은 Konsole/iTerm2/Gnome Terminal/Alacritty과 같은 터미널 에뮬레이터이며, Rust 기반으로 구축이 되어 있고, GPU 가속을 지원한다. 따라서, 렌더링 자체도 어느 정도는 빠른 편이다.

주변 사람들에게 한번 써보도록 권장하는 터미널 에뮬레이터가 세 가지 정도 있는데, Alacritty/Kitty 그리고 이 글에서 소개하는 Wezterm 정도 된다. 요즘은 Zig 기반으로 만들어진 Ghostty[1]도 추천할만 한 것 같다. 하지만, 이 글에서는 Wezterm을 소개하기로 했기 때문에, Wezterm 중심으로 소개하도록 하겠다.

Wezterm은 다음과 같은 특징을 가진다.

  • Linux, MacOS, 윈도우즈, FreeBSD 다양한 환경에서 돌아간다.
  • 한 윈도우를 여러개의 pane으로 쪼개서 분할하여 멀티플렉싱을 지원한다.(물론, 나는 ZelliJ/Tmux를 쓰기때문에 잘 이용하지는 않는 기능이다.
  • 마우스 지원이 잘 된다
  • 터미널에 표시되는 글자를 캡쳐해서 하이퍼링크로 치환이 가능하다.
    • 이건 나도 잘 이용하지는 않는 기능이지만.. T0010 같은 코드가 화면 상에 보여진다면, 특정 린터 페이지의 설명화면으로 이동하는 링크를 심을 수 있다. kiyoon님의 dotfiles 참고
  • lua로 스크립팅이 가능한데, 활용할 수 있는 방향이 굉장히 다양하다.
    • 여기에서 설명한 기능들을 최대한 활용하여 스크립팅이 가능하다.
    • API 문서를 슥 훑어보았을때, "어? 설마 이게 되나?" 싶은 생각이 든다면, 여러분이 생각하는 것도 아마 가능할지도 모른다.

Wezterm, 써보자.

Wezterm을 설치한다면 설치 안내 페이지를 참고해서 설치하면 되는데, 여러분이 Wezterm을 설치했다면 당장은 검은 화면만 뜰지도 모른다.

Wezterm을 설치하고 나서, .config/wezterm/wezterm.lua 파일을 수정해야 하는데, 당장은 아래처럼 비어있을 것이다. 파일이 없다면 만들어두는 것이 좋다.

return {}

위의 코드에서 {}는 lua에서는 테이블(다른 언어로 치면, 딕셔너리/오브젝트 같은 것)이지만, wezterm 터미널의 configuration을 나타내는 테이블이다. 여기에 몇가지 추가사항을 넣어보겠다.

터미널 에뮬레이터를 설치했는데, 터미널 에뮬레이터를 설치했으면 가장 처음부터 하는게 무엇이겠는가? 바로, 폰트를 세팅하는 것이다. 터미널 환경에서 작업할때 폰트만큼 중요한게 또 없다.

local wezterm = require("wezterm")

return {
	font = wezterm.font_with_fallback({'Cascadia Code NF', 'NanumBarunGothic'}),
	font_size = 12.0,
	line_height = 1.2,
}

폰트를 가져다 쓸때는 위의 예시와 같이 font_with_fallback 함수를 이용해서 가져다 쓸 수 있고, 그 외에도 폰트 크기를 지정하거나 행간을 지정할 수도 있다. 공식페이지에서 보았듯이, 여러분의 취향에 따라 배경색 혹은 배경이미지도 지정할 수 있는데 여러분 나름대로의 기준이 있고 욕심이 난다면 한번 도전해보는 것도 나쁘지 않을 것 같다.

위의 코드를 복사 붙여넣고 편집하다보면 느낄 수 있겠지만, wezterm은 설정파일을 편집할때 Hot Reloading을 지원한다. 이 또한, 내가 가장 애정하는 기능 중 하나이다. 혹여나 wezterm 설정 파일을 수정했을때, 문법에 오류가 있거나 설정값을 잘못 지정했을 때, 새 창으로 어떤 부분에 오류가 있는지 친절하게 Alert도 띄워준다.

API 레퍼런스를 보기만 해도 스크립팅으로 기능을 확장할 수 있는 가능성이야 당연히 많긴 하겠지만, 처음 접하는 입장에서는 어떻게 커스터마이징할 지 파악하기 난해할 수 있다.

아래에서는 내가 어떻게 Wezterm을 커스터마이징을 하고 있는지 예시를 나열하는 것으로 글을 끝내겠다. Wezterm, 믿고 써보시라.

내가 Wezterm을 응용하는 방법

1. 반투명도 조정하기

Wezterm에서 터미널 색상을 설정할때, 배경색상의 반투명도를 지정할 수 있는 옵션이 있다. 나는 여기서 단축키를 입력했을때 반투명도를 동적으로 조절하고 싶었다.

반투명도를 상수로 둘 수는 있지만, 모니터 하나 짜리의 환경에서 작업한다면 브라우저를 뒤쪽에 두고 터미널 앱을 앞에 두는 식으로 작업을 많이 하게 된다. HMR(Hot Module Reloading)이 되는 개발환경이라면, 소스코드를 편집하고 화면에 즉각적으로 반영이 되는걸 기대할텐데 이걸 탭 스위칭하면서 확인하기는 굉장히 번거롭다. 온전히 작업을 유지하다가 잠깐 확인하고 싶을때 반투명도를 변경하면 되는데도 말이다.

Wezterm에서는 이벤트를 발신할 수 있고, 다른 프로세스에서 특정 이벤트를 수신했을때 어떤 동작을 할 것인지를 정의할 수 있다. Wezterm 터미널 옵션을 수정하는것도 여기에 포함될 수 있다. 특정 단축키를 입력하면, 어떤 이벤트를 발생시킬 수 있고, 그 이벤트로 인해서 화면의 반투명도를 조정할 수 있게 했다.

local default_opacity = 0.9

local keymaps = {}

-- SHIFT + CTRL + Z 키를 누르면 반투명도를 감소시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = "Z",
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'decrease-opacity',
  }
)

-- SHIFT + CTRL + X 키를 누르면 반투명도를 증가시키는 이벤트가 발생한다.
table.insert(
  keymaps,
  {
	key = 'X',
	mods = 'SHIFT|CTRL',
	action = wezterm.action.EmitEvent 'increase-opacity',
  }
)


-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('increase-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity
  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity + 0.1
  if opacity > 1.0 then
	opacity = 1.0
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

-- "increase-opacity" 이벤트를 수신했을때, 반투명도를 증가시키는 동작을 하도록 정의한다.
wezterm.on('decrease-opacity', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  local opacity = overrides.window_background_opacity

  if opacity == nil then
	opacity = default_opacity
  end

  opacity = opacity - 0.1
  if opacity < 0.3 then
	opacity = 0.3
  end
  overrides.window_background_opacity = opacity

  window:set_config_overrides(overrides)
end)

return {
  keys = keymaps
}

2. 탭 이름 변경하기

대부분 터미널 에뮬레이터에서 탭 이름을 표시할때, 현재 탭에서 돌고 있는 프로세스의 이름을 명시할때가 많다. 그런데, 탭에 명시되어 있는 타이틀만 가지고는 각각의 탭이 어떤 역할을 하는 것인지 파악하기 어렵다. 어느 쪽이 서버를 띄우고 있는건지, 어느 쪽이 에디터 편집 화면인지, 어느 쪽이 LLM Agent를 돌리고 있는지 난해하다.

하지만, 아래처럼 wezterm.action.PromptInputLine API를 사용해서 프롬프트 입력을 받은 내용을 기반으로, 현재 활성화된 탭의 이름을 변경하는 식으로 인지부하를 줄일 수 있다.

local wezterm = require('wezterm')
local keymaps = {}

table.insert(
  keymaps,
  {
	key = '`',
	mods = 'CTRL',
	action = wezterm.action.PromptInputLine {
	  description = "Enter new name for tab",
	  action = wezterm.action_callback(function(window, _, line)
	    if line then
		  window:active_tab():set_title(line)
		end
	  end)
	}
  }
)

return {
  keys = keymaps
}

3. BEEP음 대신 화면이 번쩍이게 하기

Aider나 Claude Code 같은 LLM 에이전트가 작업을 수행 후 아예 작업이 끝났거나, 혹은 작업에 대한 승인을 요구할 때가 간혹 있다. LLM 에이전트가 작업을 수행하는걸 가만히 보고만 있을 순 없을 것이다.

Claude Code/Aider는 다행히도 응답을 하고 나서 추가적인 명령을 실행할 수 있는 옵션[2]을 제공해주는데, 거기에 간단하게 echo -ne '\007' 명령어를 넘겨줄 수 있다. 이 명령어는 엄청 어렵지는 않다. 터미널 앱에 내장된 시스템 벨 소리를 재생하는 명령어다.

작업 환경이 어디냐에 따라 다를 순 있겠지만, 작업 완료 여부를 음성으로 받기에는 물리적인 제약이 있을 수 있다. 아예 알림 센터를 이용한다고 치자. 업무 시간대에 방해금지 모드를 설정했다면 알림이 울리게 설정이 했더라도 시스템 제약상 묻힐 가능성도 있다.[3]

visual_bell 옵션을 활용하면, 터미널에 내장된 시스템 벨 소리를 울리는 대신 화면이 반짝이게 해서 다른 에이전트가 응답을 완료했다고 명시적으로 알림을 받을 수 있다. LLM 에이전트가 하는 일을 일일이 모니터링하지 않더라도, 다른 작업을 수행하는 중에 화면이 반짝이면 그때 확인하기만 하면 그만이다.

return {
	colors = {
		visual_bell = '#003355',
	},

	visual_bell = {
		fade_in_duration_ms  = 75,
		fade_out_duration_ms = 75,
		target               = 'BackgroundColor', -- 또는 'CursorColor'
	}
}

  1. Hashicorp 공동창업자인 Mitchell Hashimoto가 만든 터미널 에뮬레이터인데, OpenAI에서 Codex 시연할때 Ghostty 터미널로 시연한 바가 있다. ↩︎

  2. Aider는 notifications-command, Claude Code는 Hook이 있다 ↩︎

  3. 어떤 사람은 휴대전화를 진동모드로 해놓고, 텔레그램/디스코드로 알림쏴서 알림을 수신받는 방식을 쓰고 있는 것을 관찰한 바는 있다. ↩︎

Fedify: an ActivityPub server framework's avatar
Fedify: an ActivityPub server framework

@fedify@hollo.social

🎉 Big thanks to @2chanhaeng for his first contribution to ! He implemented the new fedify webfinger command in PR #278, which allows isolated lookups for testing configurations. This addresses the need for developers to test WebFinger functionality without performing comprehensive object retrieval.

The contribution includes:

  • A new fedify webfinger <handle> command that accepts @user@domain format handles or URIs
  • Clean JSON output of WebFinger JRD results
  • Proper error handling for invalid handles and lookup failures
  • Complete integration with help text and usage examples

This was originally filed as issue #260 and marked as a good first issue—perfect for newcomers to learn the codebase structure while contributing meaningful functionality. The PR has been merged and will be included in the upcoming Fedify 1.8.0 release.

We appreciate all first-time contributors who help make Fedify better for the entire community. Welcome aboard, ChanHaeng!

Fedify: an ActivityPub server framework's avatar
Fedify: an ActivityPub server framework

@fedify@hollo.social

🎉 Big thanks to @2chanhaeng for his first contribution to ! He implemented the new fedify webfinger command in PR #278, which allows isolated lookups for testing configurations. This addresses the need for developers to test WebFinger functionality without performing comprehensive object retrieval.

The contribution includes:

  • A new fedify webfinger <handle> command that accepts @user@domain format handles or URIs
  • Clean JSON output of WebFinger JRD results
  • Proper error handling for invalid handles and lookup failures
  • Complete integration with help text and usage examples

This was originally filed as issue #260 and marked as a good first issue—perfect for newcomers to learn the codebase structure while contributing meaningful functionality. The PR has been merged and will be included in the upcoming Fedify 1.8.0 release.

We appreciate all first-time contributors who help make Fedify better for the entire community. Welcome aboard, ChanHaeng!

Fedify: an ActivityPub server framework's avatar
Fedify: an ActivityPub server framework

@fedify@hollo.social

🎉 Big thanks to @2chanhaeng for his first contribution to ! He implemented the new fedify webfinger command in PR #278, which allows isolated lookups for testing configurations. This addresses the need for developers to test WebFinger functionality without performing comprehensive object retrieval.

The contribution includes:

  • A new fedify webfinger <handle> command that accepts @user@domain format handles or URIs
  • Clean JSON output of WebFinger JRD results
  • Proper error handling for invalid handles and lookup failures
  • Complete integration with help text and usage examples

This was originally filed as issue #260 and marked as a good first issue—perfect for newcomers to learn the codebase structure while contributing meaningful functionality. The PR has been merged and will be included in the upcoming Fedify 1.8.0 release.

We appreciate all first-time contributors who help make Fedify better for the entire community. Welcome aboard, ChanHaeng!

Fedify: an ActivityPub server framework's avatar
Fedify: an ActivityPub server framework

@fedify@hollo.social

🎉 Big thanks to @2chanhaeng for his first contribution to ! He implemented the new fedify webfinger command in PR #278, which allows isolated lookups for testing configurations. This addresses the need for developers to test WebFinger functionality without performing comprehensive object retrieval.

The contribution includes:

  • A new fedify webfinger <handle> command that accepts @user@domain format handles or URIs
  • Clean JSON output of WebFinger JRD results
  • Proper error handling for invalid handles and lookup failures
  • Complete integration with help text and usage examples

This was originally filed as issue #260 and marked as a good first issue—perfect for newcomers to learn the codebase structure while contributing meaningful functionality. The PR has been merged and will be included in the upcoming Fedify 1.8.0 release.

We appreciate all first-time contributors who help make Fedify better for the entire community. Welcome aboard, ChanHaeng!

Fedify: an ActivityPub server framework's avatar
Fedify: an ActivityPub server framework

@fedify@hollo.social

🎉 Big thanks to @2chanhaeng for his first contribution to ! He implemented the new fedify webfinger command in PR #278, which allows isolated lookups for testing configurations. This addresses the need for developers to test WebFinger functionality without performing comprehensive object retrieval.

The contribution includes:

  • A new fedify webfinger <handle> command that accepts @user@domain format handles or URIs
  • Clean JSON output of WebFinger JRD results
  • Proper error handling for invalid handles and lookup failures
  • Complete integration with help text and usage examples

This was originally filed as issue #260 and marked as a good first issue—perfect for newcomers to learn the codebase structure while contributing meaningful functionality. The PR has been merged and will be included in the upcoming Fedify 1.8.0 release.

We appreciate all first-time contributors who help make Fedify better for the entire community. Welcome aboard, ChanHaeng!

Fedify: an ActivityPub server framework's avatar
Fedify: an ActivityPub server framework

@fedify@hollo.social

🎉 Big thanks to @2chanhaeng for his first contribution to ! He implemented the new fedify webfinger command in PR #278, which allows isolated lookups for testing configurations. This addresses the need for developers to test WebFinger functionality without performing comprehensive object retrieval.

The contribution includes:

  • A new fedify webfinger <handle> command that accepts @user@domain format handles or URIs
  • Clean JSON output of WebFinger JRD results
  • Proper error handling for invalid handles and lookup failures
  • Complete integration with help text and usage examples

This was originally filed as issue #260 and marked as a good first issue—perfect for newcomers to learn the codebase structure while contributing meaningful functionality. The PR has been merged and will be included in the upcoming Fedify 1.8.0 release.

We appreciate all first-time contributors who help make Fedify better for the entire community. Welcome aboard, ChanHaeng!

Fedify: an ActivityPub server framework's avatar
Fedify: an ActivityPub server framework

@fedify@hollo.social

🎉 Big thanks to @2chanhaeng for his first contribution to ! He implemented the new fedify webfinger command in PR #278, which allows isolated lookups for testing configurations. This addresses the need for developers to test WebFinger functionality without performing comprehensive object retrieval.

The contribution includes:

  • A new fedify webfinger <handle> command that accepts @user@domain format handles or URIs
  • Clean JSON output of WebFinger JRD results
  • Proper error handling for invalid handles and lookup failures
  • Complete integration with help text and usage examples

This was originally filed as issue #260 and marked as a good first issue—perfect for newcomers to learn the codebase structure while contributing meaningful functionality. The PR has been merged and will be included in the upcoming Fedify 1.8.0 release.

We appreciate all first-time contributors who help make Fedify better for the entire community. Welcome aboard, ChanHaeng!

Fedify: an ActivityPub server framework's avatar
Fedify: an ActivityPub server framework

@fedify@hollo.social

🎉 Big thanks to @2chanhaeng for his first contribution to ! He implemented the new fedify webfinger command in PR #278, which allows isolated lookups for testing configurations. This addresses the need for developers to test WebFinger functionality without performing comprehensive object retrieval.

The contribution includes:

  • A new fedify webfinger <handle> command that accepts @user@domain format handles or URIs
  • Clean JSON output of WebFinger JRD results
  • Proper error handling for invalid handles and lookup failures
  • Complete integration with help text and usage examples

This was originally filed as issue #260 and marked as a good first issue—perfect for newcomers to learn the codebase structure while contributing meaningful functionality. The PR has been merged and will be included in the upcoming Fedify 1.8.0 release.

We appreciate all first-time contributors who help make Fedify better for the entire community. Welcome aboard, ChanHaeng!

DWeb's avatar
DWeb

@dweb@social.coop

⚡ Use the Internet Archive like a Hacker-Librarian! 🔮

Join a hands-on workshop where we’ll demystify the CLI and turn it into your super power for archiving, accessing, and uploading content to the @internetarchive.

Hosted by the @ZFAVClub, with the participation of @tommi, we’ll learn and share our experience using the awesome ia tool!

🗓️ Jul 3, 16:00 UTC (9 PDT, 18 CEST)
PARTICIPATION IS FREE

ℹ️ Info + registration: lu.ma/zv3blohp

Graphic with the title “Introduction to the Command Line Interface of Internet Archive”
ALT text detailsGraphic with the title “Introduction to the Command Line Interface of Internet Archive”
readbeanicecream's avatar
readbeanicecream

@readbeanicecream@mastodon.social

Mastodon on Toot TUI

There is nothing like a TUI (text user interface) to really help me focus. So when I stumbled on Toot TUI, I had to give it a try. Now, it is probably one of my favorite terminal applications.

readbeanicecream.surge.sh/2025

readbeanicecream's avatar
readbeanicecream

@readbeanicecream@mastodon.social

Mastodon on Toot TUI

There is nothing like a TUI (text user interface) to really help me focus. So when I stumbled on Toot TUI, I had to give it a try. Now, it is probably one of my favorite terminal applications.

readbeanicecream.surge.sh/2025

Paco Hope for Harris's avatar
Paco Hope for Harris

@paco@infosec.exchange

I am slowly oxidizing my unix CLI. A lot of people have made rust based versions of common unix utilities and some of them are REALLY good.

Like fd-find for doing essentially find . -name blah. And rg (ripgrep) which does grep -R but it's aware of git, files like pyc or .bak files, and it excludes them by default.

Now I have sd which is hopefully replacing the last thing I used perl for. I write perl -pi -e s/x/y/g a lot. Just doing a quick string replace inside a file. So sd can start doing that.

I'm also trying to get used to zellij instead of tmux and starship for modern prompt decorations like the kids do.

These kids, my friends, are welcome on my lawn.

Monsieur B.'s avatar
Monsieur B.

@jesuismonsieurb@framapiaf.org

Gens de Mastodon, j'ai une nouvelle fois besoin de votre aide.
Existerait-il un petite commande magique en bash qui permette de puiser dans un dossier contenant des images pour en faire un diaporama à partir d'elles, dans un ordre aléatoire ?

Monsieur B.'s avatar
Monsieur B.

@jesuismonsieurb@framapiaf.org

Gens de Mastodon, j'ai une nouvelle fois besoin de votre aide.
Existerait-il un petite commande magique en bash qui permette de puiser dans un dossier contenant des images pour en faire un diaporama à partir d'elles, dans un ordre aléatoire ?

JdeBP's avatar
JdeBP

@JdeBP@tty0.social · Reply to Chris Siebenmann's post

@cks

You and Ted Unangst. (-:

* news.ycombinator.com/item?id=4

Unless there are two *different* pieces about text editors today that conflate command-line and textual user interface.

Joan León's avatar
Joan León

@nucliweb@webperf.social

Bold Brew (bbrew) - A Homebrew TUI Manager

github.com/Valkyrie00/bold-bre

bbrew installed screenshot
ALT text detailsbbrew installed screenshot
Joan León's avatar
Joan León

@nucliweb@webperf.social

Bold Brew (bbrew) - A Homebrew TUI Manager

github.com/Valkyrie00/bold-bre

bbrew installed screenshot
ALT text detailsbbrew installed screenshot
grobi's avatar
grobi

@grobi@defcon.social

Please Please stop the madness! Stop using Java-script for Unix/Linux tutorials !!

As an intensive Unix and Linux user, I love to use a command-line browser. As a rule, these are links, elinks or lynx for me.

So far, they have guided me to my goal at lightning speed, are resource-saving, require little bandwidth, do not distract with unnecessary bells and whistles and, above all, they work even if the X-system fails and I have to boot without a desktop !

For me, commandline or text-based browsers are part of the Linux fire brigade and are the salvation of many users in need. But it doesn't help at all if manuals, help pages and other tutorials use Java-script!

In the example below, you can see a search query in the links browser with the parameters: "Linux close all windows commandline"

Of the 10 websites shown in the search results, 7 (!) could not be displayed at all because of Javascript, 2 did not really correspond to the parameters and only one (the github page) had a corresponding readable answer.

Does that make sense?
Absolutely not!!

Therefore, an anxious request:

Dear Tutorial Content Creators, Dear OS Developers please stop using Javascript or at least provide a plain text or html option, PLEASE PLEASE PLEASE PLEASE PLEASE

Andrew Graves :arch: :linux:'s avatar
Andrew Graves :arch: :linux:

@graves501@fosstodon.org

Is there a tool that can convert markdown files to PDFs that is not Pandoc? Pandoc has a lot of dependencies that I won't use, so I'd like to avoid that.

LavX News's avatar
LavX News

@lavxnews@ioc.exchange

Introducing kdlfmt: The Essential CLI Tool for KDL Document Formatting

The new kdlfmt CLI tool simplifies the formatting and validation of KDL (Kotlin Data Language) documents, making it an indispensable utility for developers working with this emerging data format. Buil...

news.lavx.hu/article/introduci

Introducing kdlfmt: The Essential CLI Tool for KDL Document Formatting
ALT text detailsIntroducing kdlfmt: The Essential CLI Tool for KDL Document Formatting
Karsten Schmidt's avatar
Karsten Schmidt

@toxi@mastodon.thi.ng

Just pushed a new version of thi.ng/block-fs, now with additional multi-command CLI tooling to convert & bundle a local file system tree into a single block-based binary blob (e.g. for bundling assets, or distributing a virtual filesystem as part of a web app, or for snapshot testing, or as bridge for WASM interop etc.)

Also new, the main API now includes a `.readAsObjectURL()` method to wrap files as URLs to binary blobs with associated MIME types, thereby making it trivial to use the virtual filesystem for sourcing stored images and other assets for direct use in the browser...

(Ps. For more context see other recent announcement: mastodon.thi.ng/@toxi/11426498)

Screenshot excerpt from the project readme (link in post) containing information about the CLI wrapper, as well as example usage (here to convert/bundle as filesystem tree)
ALT text detailsScreenshot excerpt from the project readme (link in post) containing information about the CLI wrapper, as well as example usage (here to convert/bundle as filesystem tree)
Screenshot excerpt from the project readme (link in post) containing information about the CLI wrapper, as well as example usage (here to list contents of an already bundled filesystem)
ALT text detailsScreenshot excerpt from the project readme (link in post) containing information about the CLI wrapper, as well as example usage (here to list contents of an already bundled filesystem)
readbeanicecream's avatar
readbeanicecream

@readbeanicecream@mastodon.social

Zettelkasten on the CLI

Let's take a look at my Zettelkasten notetaking workflow on the Linux Command Line. Trust me, it's simple.

readbeanicecream.surge.sh/2025

indieweb

Manos Pitsidianakis's avatar
Manos Pitsidianakis

@epilys@chaos.social

Stupid-but-works tip on how to add inline documentation comments for multi-line shell commands in scripts: Combine command substitution with grave accents "`" and the do-nothing built-in command ":":

```shell
% ls \
> -h `: this is a comment` \
> -a `: this is another comment` \
> -t `: more commentssss`
```

Manos Pitsidianakis's avatar
Manos Pitsidianakis

@epilys@chaos.social

Stupid-but-works tip on how to add inline documentation comments for multi-line shell commands in scripts: Combine command substitution with grave accents "`" and the do-nothing built-in command ":":

```shell
% ls \
> -h `: this is a comment` \
> -a `: this is another comment` \
> -t `: more commentssss`
```

readbeanicecream's avatar
readbeanicecream

@readbeanicecream@mastodon.social

Zettelkasten on the CLI

Let's take a look at my Zettelkasten notetaking workflow on the Linux Command Line. Trust me, it's simple.

readbeanicecream.surge.sh/2025

indieweb

Hugo van Kemenade's avatar
Hugo van Kemenade

@hugovk@mastodon.social · Reply to Hugo van Kemenade's post

Just released: pypistats 1.9.0 🚀

pypistats is CLI to show download stats from PyPI

pypi.org/project/pypistats/1.9

* Replace deprecated classifier with licence expression (PEP 639)
* Remove GitHub attestation, uses PyPI attestations instead (PEP 740)
* Add input validation for total and fix --monthly with no mirror
* Update docs for recent command

Terminal output of running "pypistats python_minor pillow", showing a table of Python versions sorted by how many downloads each is responsible for.
ALT text detailsTerminal output of running "pypistats python_minor pillow", showing a table of Python versions sorted by how many downloads each is responsible for.
Fedi.Tips's avatar
Fedi.Tips

@FediTips@social.growyourown.services

Here's a very brief tip for the more techy people on here:

You can use Mastodon (and compatible servers) through command lines and text-based interfaces with the free open source client "toot":

➡️ toot.bezdomni.net

There are lots more details on the developer's website.

Fedi.Tips's avatar
Fedi.Tips

@FediTips@social.growyourown.services

Here's a very brief tip for the more techy people on here:

You can use Mastodon (and compatible servers) through command lines and text-based interfaces with the free open source client "toot":

➡️ toot.bezdomni.net

There are lots more details on the developer's website.

scy's avatar
scy

@scy@chaos.social

`lowdown -tterm` produces pretty nice rendering in the .

kristaps.bsd.lv/lowdown/

Screenshot of an article talking about tab-completion for bash aliases, rendered in plain text. Monospace parts are rendered blue & bold, links are yellow and bold and followed by the URL they're linking to in green and underlined. Code blocks are indented, bold, and with a blue line to their left.
ALT text detailsScreenshot of an article talking about tab-completion for bash aliases, rendered in plain text. Monospace parts are rendered blue & bold, links are yellow and bold and followed by the URL they're linking to in green and underlined. Code blocks are indented, bold, and with a blue line to their left.
maxlath's avatar
maxlath

@maxlath@mastodon.social · Reply to Sebastian Lasse's post

@sl007 which command are you using? Somethink like the following could work:

wd data Q183 --props P3086 --simplify --keep richvalues,qualifiers

freespiritlinux69 :fedi:'s avatar
freespiritlinux69 :fedi:

@freespiritlinux69@fedi.at

Schönen guten Morgen,

Ich habe mich entschieden, ein kleines Tutorial über CLI-Befehle unter Linux zu erstellen.
CLI steht für Command Line Interface, was auf Deutsch als Befehlszeilenschnittstelle bezeichnet wird. Es handelt sich um eine textbasierte Benutzeroberfläche, die es Benutzern ermöglicht, mit einem Computer oder einem Betriebssystem zu interagieren, indem sie Befehle in Form von Text eingeben.
In Linux kann das sogenannte Terminal zur Eingabe von CLI-Befehlen verwendet werden.

Bitte teilt das mit eurer , damit mehr Menschen darauf aufmerksam werden. Dieses Tutorial richtet sich an Anfänger, die das Terminal unter Linux nicht als furchterregendes Monster betrachten, sondern effizient damit arbeiten möchten.

DANKESCHÖN

Der Link führt direkt zum Thread mit dem Tutorial und kann bei Bedarf gespeichert werden.

fedi.at/@freespiritlinux69/114

Tuist's avatar
Tuist

@tuist@fosstodon.org

Soon our Noora single-choice prompt component will support filtering thanks to @finnvoorhees's brilliant work in this PR:
github.com/tuist/Noora/pull/19

Tuist's avatar
Tuist

@tuist@fosstodon.org

Soon our Noora single-choice prompt component will support filtering thanks to @finnvoorhees's brilliant work in this PR:
github.com/tuist/Noora/pull/19

Artemis's avatar
Artemis

@artemissian@fosstodon.org

Alternative tools to check out and try:

bat github.com/sharkdp/bat
bottom github.com/ClementTsang/bottom
broot github.com/Canop/broot
btop github.com/aristocratos/btop
cheat github.com/cheat/cheat
choose github.com/theryangeary/choose
curlie github.com/rs/curlie
delta github.com/dandavison/delta
doggo github.com/mr-karan/doggo
dust github.com/bootandy/dust
duf github.com/muesli/duf
dysk github.com/Canop/dysk
eza github.com/eza-community/eza
fd github.com/sharkdp/fd
fzf github.com/junegunn/fzf

Artemis's avatar
Artemis

@artemissian@fosstodon.org

Alternative tools to check out and try:

bat github.com/sharkdp/bat
bottom github.com/ClementTsang/bottom
broot github.com/Canop/broot
btop github.com/aristocratos/btop
cheat github.com/cheat/cheat
choose github.com/theryangeary/choose
curlie github.com/rs/curlie
delta github.com/dandavison/delta
doggo github.com/mr-karan/doggo
dust github.com/bootandy/dust
duf github.com/muesli/duf
dysk github.com/Canop/dysk
eza github.com/eza-community/eza
fd github.com/sharkdp/fd
fzf github.com/junegunn/fzf

hyaline.systems's avatar
hyaline.systems

@hyalinesystems@mastodon.social

📼 Command line video magic for ARTISTS

A cookbook by @madskjeldgaard for audio and video processing on the command line – with examples!

Includes how to generate a spectrum video from an audio file. How to combine an audio file and an image into a video. Among other things.

And it includes full scripts and examples for for-loops, so you could do this on tons of audio files, if you so fancied 🤠

hyaline.systems/blog/ffmpeg-fo

ploum's avatar
ploum

@ploum@mamot.fr

If you are a Unix nerd and wish you spend less time using your mouse while watching flashy colors, I recommend that you give Offpunk a try:

offpunk.net/

I’m trying to make it easier to get started with offpunk. Feedbacks and discussions are welcome on the mailing-list :

lists.sr.ht/~lioploum/offpunk-

or on the fediverse, using the hashtag. Or on your blog. That would be awesome to read blog posts about people using offpunk

Orhun Parmaksız 👾's avatar
Orhun Parmaksız 👾

@orhun@fosstodon.org

I found the ultimate CLI tool for processing CSV files! 🔥

🪄✨ **xan**: The CSV magician.

💯 Supports expressions, parallelism, advanced filtering, sorting, and visualizations.

🦀 Written in Rust & uses @ratatui_rs

⭐ GitHub: github.com/medialab/xan

ploum's avatar
ploum

@ploum@mamot.fr

If you are a Unix nerd and wish you spend less time using your mouse while watching flashy colors, I recommend that you give Offpunk a try:

offpunk.net/

I’m trying to make it easier to get started with offpunk. Feedbacks and discussions are welcome on the mailing-list :

lists.sr.ht/~lioploum/offpunk-

or on the fediverse, using the hashtag. Or on your blog. That would be awesome to read blog posts about people using offpunk

Orhun Parmaksız 👾's avatar
Orhun Parmaksız 👾

@orhun@fosstodon.org

I found the ultimate CLI tool for processing CSV files! 🔥

🪄✨ **xan**: The CSV magician.

💯 Supports expressions, parallelism, advanced filtering, sorting, and visualizations.

🦀 Written in Rust & uses @ratatui_rs

⭐ GitHub: github.com/medialab/xan

nev's avatar
nev

@nev@bananachips.club · Reply to Julia's Reruns Bot's post

@b0rk_reruns ok so i have a kind of cursed question. often i'm doing something like `for file in $(ls *.txt); do echo ${file%.txt}; done`. why won't bash let me do ${$(ls *.txt)%.txt} and is there a better way to do it

(cc @b0rk)

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

, an -powered app for summarizing web pages, now distributes the official executables for Linux, macOS, and Windows!

https://github.com/dahlia/yoyak/releases/tag/0.3.0

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

, an -powered app for summarizing web pages, now distributes the official executables for Linux, macOS, and Windows!

https://github.com/dahlia/yoyak/releases/tag/0.3.0

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social

, an -powered app for summarizing web pages, now distributes the official executables for Linux, macOS, and Windows!

https://github.com/dahlia/yoyak/releases/tag/0.3.0

blinry's avatar
blinry

@blinry@chaos.social

I'm looking for a command line tool that allows watching a video file together on two computers, with synchronized play/pause, like these "watch party" sites, but inside a local network.

In the simplest case, it could be a Bash command streaming/decoding a local file at the same time, and another person could receive that stream…? Has anyone seen something like that?

blinry's avatar
blinry

@blinry@chaos.social

I'm looking for a command line tool that allows watching a video file together on two computers, with synchronized play/pause, like these "watch party" sites, but inside a local network.

In the simplest case, it could be a Bash command streaming/decoding a local file at the same time, and another person could receive that stream…? Has anyone seen something like that?

ploum's avatar
ploum

@ploum@mamot.fr

Released Offpunk 2.5 which add custom "aliases" and improve compatibility with and version < 3.11

What is Offpunk?

offpunk.net/whatisoffpunk.html

You are welcome to discuss and ask questions on the offpunk-users list:

lists.sr.ht/~lioploum/offpunk-

If you are familiar with python development, join the offpunk-devel list to help intregrate offpunk and unmerdify, a new library developed by @vjousse :

lists.sr.ht/~lioploum/offpunk-

ploum's avatar
ploum

@ploum@mamot.fr

Released Offpunk 2.5 which add custom "aliases" and improve compatibility with and version < 3.11

What is Offpunk?

offpunk.net/whatisoffpunk.html

You are welcome to discuss and ask questions on the offpunk-users list:

lists.sr.ht/~lioploum/offpunk-

If you are familiar with python development, join the offpunk-devel list to help intregrate offpunk and unmerdify, a new library developed by @vjousse :

lists.sr.ht/~lioploum/offpunk-

Robert Kingett's avatar
Robert Kingett

@WeirdWriter@caneandable.social

So, I am giving a try. It’s a command line utility that will allow you to copy things from one cloud storage to the other with ease, sync one way or buy directionally, and Mount cloud storage as virtual drives on your machine so you can mount things like Google Drive, iCloud Drive, and even OneDrive without using any of their bloated and inaccessible software. Of course, the first thing I tried to do with it, it’s not capable of Yet. I tried to copy my writing from an off-line hard drive to three different cloud services with one command. That’s not possible as of yet, but I would still highly recommend this tool even if I’m sure I’m not utilizing it to its full glory as of yet. , ,

nickbearded's avatar
nickbearded

@nickbearded@mastodon.social

The website is live!

bashcore.org/

:rss: Qiita - 人気の記事's avatar
:rss: Qiita - 人気の記事

@qiita@rss-mstdn.studiofreesia.com

JavaでCLIツールを作る
qiita.com/umiushi_1/items/4da6

Levi Beach's avatar
Levi Beach

@levibeach@merveilles.town · Reply to Levi Beach's post

Thinking through some settings UI this morning.

Mockup of ADSR settings for command line synthesizer.
ALT text detailsMockup of ADSR settings for command line synthesizer.
Stephen Ramsay's avatar
Stephen Ramsay

@sramsay@hcommons.social

I'm pleased to present a new blog post -- "Beautiful Documents with Groff (Part II)" stephenramsay.net/posts/groff- -- only a year-and-a-half after "Beautiful Documents with Groff (Part I)" stephenramsay.net/posts/groff-

Of interest, perhaps, to users of and/or , cultists, and digital document nerds. Discusses , , , and even (though not the kind that makes you sneeze).

Levi Beach's avatar
Levi Beach

@levibeach@merveilles.town · Reply to Levi Beach's post

So I guess it's happening and I'm really excited to explore all the possibilities. Using the Node binding for Rust's Web Audio API to create sound, which means I can do stuff like impulse response to model spaces!

Two command line windows, one running Orca, the other running something called "HORSE SYNTH". Extremely basic controls for wave shape and ADSR are visible.
ALT text detailsTwo command line windows, one running Orca, the other running something called "HORSE SYNTH". Extremely basic controls for wave shape and ADSR are visible.
Hugo van Kemenade's avatar
Hugo van Kemenade

@hugovk@mastodon.social · Reply to Hugo van Kemenade's post

Just released! stravavis 0.5.0 🚀

Create artistic visualisations with your exercise data.

pypi.org/project/stravavis/0.5

🚴 Drop support for EOL Python 3.8

🏃 Skip segments in GPX tracks with empty trkseg

🛶 Fix pandas warnings

A heatmap of Helsinki and surrounding with black lines indicating bike rides.
ALT text detailsA heatmap of Helsinki and surrounding with black lines indicating bike rides.
Hugo van Kemenade's avatar
Hugo van Kemenade

@hugovk@mastodon.social · Reply to Hugo van Kemenade's post

Just released: blurb 1.3.0 🚀

blurb is the CLI we use for managing CPython's news/changelog entries.

🗞️ Add support for Python 3.13

🗞️ Drop support for Python 3.8

🗞️ Generate digital attestations for PyPI (PEP 740)

🗞️ Allow running blurb test from blurb-* directories by

🗞️ Add version subcommand

🗞️ Generate __version__ at build to avoid slow importlib.metadata

pypi.org/project/blurb/1.3.0/

Hugo van Kemenade's avatar
Hugo van Kemenade

@hugovk@mastodon.social · Reply to Hugo van Kemenade's post

Just released: norwegianblue 0.19.0 🚀

🦜 Drop support for Python 3.8

🦜 Generate digital attestations for PyPI (PEP 740)

🦜 Test with tox-uv

🦜 Lint with pre-commit-uv

pypi.org/project/norwegianblue

norwegianblue is a CLI to show EOLs from endoflife.date

A CLI call of "eol python" showing a coloured table of each Python feature release, its latest x.y.z version and date, and the dates of when it enters security-only and EOL.
ALT text detailsA CLI call of "eol python" showing a coloured table of each Python feature release, its latest x.y.z version and date, and the dates of when it enters security-only and EOL.
Hugo van Kemenade's avatar
Hugo van Kemenade

@hugovk@mastodon.social · Reply to Hugo van Kemenade's post

Just released: pepotron 1.3.0 🚀

🔩 Generate digital attestations for PyPI (PEP 740)

🔩 Drop support for Python 3.8

🔩 Generate __version__ at build to avoid slow importlib.metadata

🔩 Test on CI with uv

pypi.org/project/pepotron/1.3.

Pepotron is a CLI for opening PEPs in your browser. For example, try:

$ pep 8

$ pep 3.14

$ pep dead batteries

$ pep calendar

Hugo van Kemenade's avatar
Hugo van Kemenade

@hugovk@mastodon.social · Reply to Hugo van Kemenade's post

Just released: pypistats 1.7.0 🚀

📈 Generate digital attestations for PyPI (PEP 740)

📉 Drop support for EOL Python 3.8

📈 Generate __version__ at build to avoid slow importlib.metadata

pypi.org/project/pypistats/1.7

Example use, showing an ASCII chart:

❯ pypistats python_minor pillow --last-month
┌──────────┬─────────┬─────────────┐
│ category │ percent │   downloads │
├──────────┼─────────┼─────────────┤
│ 3.10     │  16.80% │  20,297,555 │
│ 3.11     │  15.78% │  19,062,442 │
│ 3.7      │  14.86% │  17,958,611 │
│ 3.9      │  13.68% │  16,530,171 │
│ 3.8      │  12.32% │  14,887,891 │
│ 3.6      │  11.73% │  14,169,137 │
│ 3.12     │   9.56% │  11,548,054 │
│ null     │   4.73% │   5,716,677 │
│ 2.7      │   0.50% │     598,393 │
│ 3.13     │   0.03% │      34,987 │
│ 3.5      │   0.02% │      20,237 │
│ 3.4      │   0.00% │         817 │
│ 3.14     │   0.00% │         232 │
│ 3.3      │   0.00% │          14 │
│ 3.1      │   0.00% │           5 │
│ 3.2      │   0.00% │           2 │
│ Total    │         │ 120,825,225 │
└──────────┴─────────┴─────────────┘

Date range: 2024-09-01 - 2024-09-30
ALT text detailsExample use, showing an ASCII chart: ❯ pypistats python_minor pillow --last-month ┌──────────┬─────────┬─────────────┐ │ category │ percent │ downloads │ ├──────────┼─────────┼─────────────┤ │ 3.10 │ 16.80% │ 20,297,555 │ │ 3.11 │ 15.78% │ 19,062,442 │ │ 3.7 │ 14.86% │ 17,958,611 │ │ 3.9 │ 13.68% │ 16,530,171 │ │ 3.8 │ 12.32% │ 14,887,891 │ │ 3.6 │ 11.73% │ 14,169,137 │ │ 3.12 │ 9.56% │ 11,548,054 │ │ null │ 4.73% │ 5,716,677 │ │ 2.7 │ 0.50% │ 598,393 │ │ 3.13 │ 0.03% │ 34,987 │ │ 3.5 │ 0.02% │ 20,237 │ │ 3.4 │ 0.00% │ 817 │ │ 3.14 │ 0.00% │ 232 │ │ 3.3 │ 0.00% │ 14 │ │ 3.1 │ 0.00% │ 5 │ │ 3.2 │ 0.00% │ 2 │ │ Total │ │ 120,825,225 │ └──────────┴─────────┴─────────────┘ Date range: 2024-09-01 - 2024-09-30
marius's avatar
marius

@mariusor@metalhead.club

Man, I enjoy the API of but sometimes bending one's UI to its paradigm is a pain in the butt.

Summer Emacs 🏳️‍🌈🇺🇦's avatar
Summer Emacs 🏳️‍🌈🇺🇦

@summeremacs@fashionsocial.host

I just posted a new file about how I got into using , , the , and other things.

Here it is: summeremacs.github.io/posts/ho

And no @daviwil, I'm still not starting a blog to post this stuff. 😀

Edit: I was wrong. @daviwil was right. I am leaving my post up here as a victory for him. 🤣

Jelloeater 🥥🌴🚫🔙's avatar
Jelloeater 🥥🌴🚫🔙

@jelloeater@mastodon.social

Got bored, wrote a timestamp app in
github.com/Jelloeater/stampy

matclab's avatar
matclab

@matclab@mamot.fr

Je relance mon blog, en modifiant le système de commentaire pour qu'il utilise mastodon.

Je vais mettre quelques liens ici et commencer par un retour d'expérience sur l'utilisation de `ledger-cli` pour faire mes comptes (que j'utilise toujours).

ontoblogie.clabaut.net/posts/2

Charlie O’Hara's avatar
Charlie O’Hara

@whalecoiner@indieweb.social

Does anyone have a recommendation for a CLI boilerplate text file creator? I need something to help with using my personal website better. I’m thinking of something where I can type “<app> new post” or “<app> new note” and a markdown file of appropriate frontmatter stubs is created, in a predefined directory. It’d have to have some kind of template system available. Know of anything?

OS/1337's avatar
OS/1337

@OS1337@infosec.space

For everyone wanting to test out OS/1337 there's good news:

You can just clone the repo or pull it as :
github.com/OS-1337/OS1337

and then just run ./scripts/build.sh

and within a few mins it'll spit out a bootable image in /build/0.CORE/ to put on a 3,5" FDD or run in a VM [may it be or ]...

Thanks to @SweetAIBelle for the generous contributions!

Servio Paladines's avatar
Servio Paladines

@servio@libretics.org

Presentación

Imagen del Ñu la mascota oficial del movimiento del Software Libre.

: un lugar de encuentro, debate, investigación, desarrollo y difusión acerca de los usos sociales de la tecnología.

Contacto:

Web https://www.libretics.org

Radio https://libretics.org/radio

: podcast.libretics.org/

Grupo xmpp:hacklab-libretics@salas.gnlug…

Grupo : i.delta.chat/#FF36E74BCB6E7C00

Blog: http://3puc73jz3pbflplwe7y5hkopdoq…

Me gusta mucho el concepto de la internet pequeña: 1 persona = 1 servidor = 1 página web. 🧑‍💻🧰🐃🐧🇪🇨

Imagen del Ñu la mascota oficial del movimiento del Software Libre.
ALT text detailsImagen del Ñu la mascota oficial del movimiento del Software Libre.
scy's avatar
scy

@scy@chaos.social

`lowdown -tterm` produces pretty nice rendering in the .

kristaps.bsd.lv/lowdown/

Screenshot of an article talking about tab-completion for bash aliases, rendered in plain text. Monospace parts are rendered blue & bold, links are yellow and bold and followed by the URL they're linking to in green and underlined. Code blocks are indented, bold, and with a blue line to their left.
ALT text detailsScreenshot of an article talking about tab-completion for bash aliases, rendered in plain text. Monospace parts are rendered blue & bold, links are yellow and bold and followed by the URL they're linking to in green and underlined. Code blocks are indented, bold, and with a blue line to their left.
Jean-Mi à peu près expert's avatar
Jean-Mi à peu près expert

@nojhan@mamot.fr

Il parait que j'aurais dû faire une depuis 6 ans, alors voilà. Ici, je pouet :
– science (recherche appliqué en algorithmique de l', en ce moment assez saoulé par son dévoiement corporate),
– design & illustration (souvent vectorielle sous ),
– code libre (auteur de  : , , …),
– politique (anar gauchiste, centriste repenti, radicalisé par le macronisme),
– sondages bizarres (neuroatypique tentant de comprendre comment ça marche dans votre tête).

Elijah Manor's avatar
Elijah Manor

@elijahmanor@hachyderm.io

npx elijahmanor

> Updated to include mastodon instance

business card

📌

Terminal output from the "npx elijahmanor" command
ALT text detailsTerminal output from the "npx elijahmanor" command
Soso's avatar
Soso

@sgued@pouet.chapril.org

🇫🇷 Étudiant, passionné de logiciels libres. J'ai créé peertube-viewer, un petit outil en ligne de commande pour naviguer les vidéos , dans le même esprit que youtube-viewer

🇬🇧 Student, passionate by . I created peertube-viewer, a small tool to browse peertube instances, quite similar to youtube-viewer.