개발 환경 설정 (2025-2026)

OS 공통

글꼴

OS 구분 없이 설치할 글꼴 목록

Pretendard

https://github.com/orioncactus/pretendard/releases

Pretendard와 Pretendard Variable만 설치한다.

나눔바른고딕

https://hangeul.naver.com/2017/nanum

D2Coding

https://github.com/naver/d2codingfont/releases

기본 버전만 설치한다 (bold 포함).


macOS/Ubuntu 공통

macOS/Ubuntu Git 설정

~/.gitconfig를 설정한다. user.nameuser.email을 수정해야 한다.

먼저 fzf 설치가 필요하다! Interactive CLI 프로그램 이런 거 따로 설치할 필요없이, CLI에서 화살표, 탭 몇 번 눌러서 브랜치를 선택할 수 있다. (git branch | grep -v '^\*' | fzf -m | xargs git branch -D를 처음 썼을 때의 감동이란...)

[user]
    name = Your Name
    email = id@email.com
[core]
    editor = vim
    ignorecase = false
[fetch]
    recurseSubmodules = on-demand
[push]
    default = simple
[alias]
    st = status
    ci = commit
    cinv = commit --no-verify
    ciam = commit --amend
    ciamnv = commit --amend --no-verify
    br = branch
    ibrs = "!f() { git branch --color=always | fzf -m --ansi | perl -pe 's/\\e\\[[0-9;]*m//g' | cut -c 3-; }; f"
    brd = branch -D
    ibrd = "!f() { git branch | grep -v '^[*+]' | awk '{print $NF}' | fzf -m | xargs -I{} git brd {} \"$@\"; }; f"
    chp = cherry-pick
    co = checkout
    ico = "!f() { git branch --color=always | fzf --ansi | perl -pe 's/\\e\\[[0-9;]*m//g' | awk '{print $NF}' | xargs -I{} git checkout {} \"$@\"; }; f"
    irtco = "!f() { git branch -r --color=always | fzf --ansi | perl -pe 's/\\e\\[[0-9;]*m//g' | awk '{print $NF}' | xargs -I{} git checkout {} \"$@\"; }; f"
    cobr = checkout -b
    fe = fetch
    fep = fetch --prune
    fepo = fetch --prune origin
    logp = log --pretty='%C(blue)%ai  %C(brightmagenta)%<(18,trunc)%an  %C(brightblack)%h  %C(reset)%s %C(cyan)%d'
    pu = push
    puu = push -u
    puuo = push -u origin HEAD

끔찍하게도 리눅스와 다르게, macOS에서는 Git이 기본적으로 대소문자를 구분하지 않는다. core.ignorecase = false 설정을 하지 않으면, 몇 시간을 허비할 수도 있다.

fzf -m은 상호작용 셸에서 다중 선택이 가능하다. Tab 키로 선택하고, Shift-Tab 키로 해제한다.

git puuo를 하면, 위험한 push.autoSetupRemote = true 설정 없이도 현재 HEAD 브랜치를 같은 이름으로 생성하면서 upstream 설정까지 할 수 있다.

.gitconfig에서는 backslash(\) escape를 해줘야 한다는 사실도 주의해야 함.

macOS/Ubuntu VIM 설정

~/.vimrc에 아래 문장을 추가한다.

  • set ruler: 줄과 칼럼 번호가 보인다.
  • syntax on: Git commit 시 색깔이 보인다.

set nu (줄 번호가 보인다.)는 사용하지 않는다. 평소에는 터미널 너비만 줄이는 것 같다...


masOS

Git wrapper

Git을 영문으로 실행하는 wrapper임. PATH 등록 필요함.

mkdir -p ~/.local/bin


cat > ~/.local/bin/git << 'EOF'
#!/bin/sh
# Execute Git in English.
LANG=en_US.UTF-8 exec /usr/bin/git "$@"
EOF


chmod +x ~/.local/bin/git

(macOS) Shell - zsh

2023년부터 Bash 대신 zsh를 기본으로 사용한다. Login shell 기본 스크립트는 ~/.zprofile을, interactive shell 기본 스크립트는 ~/.zshrc를 수정한다.

최신 macOS의 기본 shell은 zsh이다.

~/.zshrc 일부

.bashrc와 호환되지 않는다.

# Use the simple primary prompt string.
export PS1="%1~ %# "


# Bind custom shortcuts.
# (Enable word-jump shortcuts without changing terminal program key mappings.)
bindkey "^[[1;5C" forward-word
bindkey "^[[1;5D" backward-word


# Homebrew 1
export PATH="/opt/homebrew/bin:$PATH"


# Homebrew 2
export PATH="/usr/local/bin:$PATH"


# NVM
# ('--no-use' is required to prevent slow performance! Must use 'nvm use' or 'nvm use default' only
# if needed.)
# https://github.com/nvm-sh/nvm/issues/1261
export NVM_DIR=~/.nvm
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" --no-use


# Claude Code path
export PATH="$HOME/.local/bin:$PATH"


# Claude Code aliases
alias cld='claude'
alias cldsp='claude --dangerously-skip-permissions'


# Claude Code Switch(CCS)
# (runs with NVM default node to avoid project version conflicts.)
function ccs() {
    (
        if type nvm &>/dev/null; then
            nvm use default
        fi
        command ccs "$@"
    )
}
alias ccssp='ccs --dangerously-skip-permissions'


# Codex
# (runs with NVM default node to avoid project version conflicts.)
function codex() {
    (
        if type nvm &>/dev/null; then
            nvm use default
        fi
        command codex "$@"
    )
}


# fzf
source <(fzf --zsh)


# Git in English
alias git='LANG=en_US.UTF-8 git'


# compinit
# (It activates Git autocompletion too.)
# https://stackoverflow.com/a/58517668
autoload -Uz compinit && compinit


# Zellij shell completion
# https://github.com/zellij-org/zellij/issues/1933#issuecomment-3020581413
[ -x "$(command -v zellij)" ] \
    && . <( zellij setup --generate-completion zsh | sed -E "
/^autoload -U is-at-least/a\\
\\
_zellij_sessions() {\\
    local line sessions desc; sessions=(\"\${(@f)\$(zellij ls -n)}\")\\
    local -a session_names_with_desc\\
    for line in \"\${sessions[@]}\"; do\\
        session_name=\${line%% *}\\
        desc=\${line#* }\\
        session_names_with_desc+=(\"\$session_name:\$desc\")\\
    done\\
    _describe -t sessions 'active session' session_names_with_desc\\
}
s/^(attach)/\1|a/
s/::session-name -- Name of the session to attach to:/::session-name:_zellij_sessions/
s/^(kill-session)/\1|k/
s/::target-session -- Name of target session:/::target-session:_zellij_sessions/
s/^(delete-session)/\1|d/
s/^(_(zellij) ).*/compdef \1\2/
")


# ghq custom functions
# https://shunk031.me/post/ghq-gwq-fzf-worktree/
function ghq-path() {
    ghq list --full-path | fzf
}

function cghq() {
    # Must use 'local' separately to capture the return code of fzf.
    local TARGET_PATH
    TARGET_PATH=$(ghq list | fzf)
    local RET=$?
    if [[ "$RET" -ne 0 ]]; then
        return $RET
    fi

    local TARGET_ABSOLUTE_PATH="$(ghq root)/$TARGET_PATH"
    cd "$TARGET_ABSOLUTE_PATH" \
        && echo "$TARGET_PATH" \
        || exit 1
}

function cghq-rename-tab() {
    cghq
    local RET=$?
    if [[ "$RET" -ne 0 ]]; then
        return $RET
    fi

    local REPO_NAME="${PWD##*/}"
    local TAB_NAME="${REPO_NAME//./-}"

    # Rename this tab if in Zellij.
    if [[ -n ${ZELLIJ} ]]; then
        zellij action rename-tab "$TAB_NAME"
    # Rename this window if in Tmux.
    elif [[ -n ${TMUX} ]]; then
        tmux rename-window "$TAB_NAME"
    fi
}


# gwq shell completion
[ -x "$(command -v gwq)" ] && source <(gwq completion zsh)


# gwq custom functions
function mygwq-ls() {
    local JSON
    JSON=$(gwq ls --json)
    local RET=$?
    if [[ "$RET" -ne 0 ]]; then
        return $RET
    fi

    local -a PATHS BRANCHES MAINS

    while IFS= read -r LINE; do
        PATHS+=("${LINE/#$HOME/~}")
    done < <(jq -r '.[].path' <<< "$JSON")

    while IFS= read -r LINE; do
        BRANCHES+=("$LINE")
    done < <(jq -r '.[].branch' <<< "$JSON")

    while IFS= read -r LINE; do
        MAINS+=("$LINE")
    done < <(jq -r '.[].is_main' <<< "$JSON")

    local CURRENT_TOPLEVEL=$(git rev-parse --show-toplevel 2>/dev/null)

    local I PREFIX LAST_DIR_COLOR
    for (( I = 1; I <= ${#PATHS[@]}; I++ )); do
        if [[ "${PATHS[$I]}" == "${CURRENT_TOPLEVEL/#$HOME/~}" ]]; then
            PREFIX=$'\033[92m* \033[0m'
        else
            PREFIX="  "
        fi
        if [[ "${MAINS[$I]}" == "true" ]]; then
            LAST_DIR_COLOR="33"
        else
            LAST_DIR_COLOR="95"
        fi
        printf "%s\033[90m%s/\033[%sm%s\033[0m  \033[36m%s\033[0m\n" \
            "$PREFIX" "${PATHS[$I]%/*}" "$LAST_DIR_COLOR" "${PATHS[$I]##*/}" "${BRANCHES[$I]}"
    done
}

function mygwq-irm() {
    local JSON
    JSON=$(gwq ls --json)
    local RET=$?
    if [[ "$RET" -ne 0 ]]; then
        return $RET
    fi

    local CURRENT_TOPLEVEL=$(git rev-parse --show-toplevel 2>/dev/null)

    local -a ITEMS
    local DISPLAY_PATH
    while IFS= read -r ENTRY_PATH; do
        [[ "$ENTRY_PATH" == "$CURRENT_TOPLEVEL" ]] && continue
        ENTRY_PATH="${ENTRY_PATH/#$HOME/~}"
        DISPLAY_PATH=$'\033[90m'"${ENTRY_PATH%/*}/"$'\033[95m'"${ENTRY_PATH##*/}"$'\033[0m'
        ITEMS+=("$DISPLAY_PATH")
    done < <(jq -r '.[] | select(.is_main == false) | .path' <<< "$JSON")

    if (( ${#ITEMS[@]} == 0 )); then
        echo "No target non-main worktrees found."
        return 0
    fi

    # Must use 'local' separately to capture the return code of fzf.
    local SELECTED
    SELECTED=$(printf '%s\n' "${ITEMS[@]}" | fzf --ansi)
    local RET=$?
    if [[ "$RET" -ne 0 ]]; then
        return $RET
    fi

    local CLEAN_PATH=$(sed $'s/\033\\[[0-9;]*m//g' <<< "$SELECTED")

    echo "Removing: $CLEAN_PATH"
    gwq rm -f "$@" "${CLEAN_PATH/#\~/$HOME}"
}


# jenv
export PATH="$HOME/.jenv/bin:$PATH"
[ -x "$(command -v jenv)" ] && eval "$(jenv init -)"


# PNPM
# pnpm
export PNPM_HOME="$HOME/Library/pnpm"
case ":$PATH:" in
  *":$PNPM_HOME:"*) ;;
  *) export PATH="$PNPM_HOME:$PATH" ;;
esac
# pnpm end


# pyenv
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv > /dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
command -v pyenv > /dev/null && eval "$(pyenv init -)"


# Cargo
export PATH="$HOME/.cargo/bin:$PATH"


# pchuri Confluence CLI
# (runs with NVM default node to avoid project version conflicts.)
function confluence() {
    (
        if type nvm &>/dev/null; then
            nvm use default
        fi
        command confluence "$@"
    )
}


# pchuri Jira CLI
# (runs with NVM default node to avoid project version conflicts.)
function jira() {
    (
        if type nvm &>/dev/null; then
            nvm use default
        fi
        command jira "$@"
    )
}


# iTerm2
test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh"


# Rancher Desktop
### MANAGED BY RANCHER DESKTOP START (DO NOT EDIT)
export PATH="/Users/user/.rd/bin:$PATH"
### MANAGED BY RANCHER DESKTOP END (DO NOT EDIT)


# Hadoop
export HADOOP_HOME="$HOME/apps/hadoop"

터미널의 키 매핑을 바꾸지 않고도, 단어 사이의 커서 이동을 가능하게 만든다. 이걸 macOS의 셸 설정으로 해야, SSH 원격 접속 시에도 키 매핑이 어울리게끔 할 수 있는 것이다.

zsh의 Git autocompletion은 다음 웹페이지를 참고한다.

https://stackoverflow.com/a/58517668

.zshrc가 느리다고 생각이 되면, ZProf로 프로파일링해서 개선점을 찾아볼 수 있다.

(macOS) Shell - bash

Bash 단축키 변경

터미널의 키 매핑을 바꾸지 않고도, 단어 사이의 커서 이동을 가능하게 만든다. 이걸 macOS의 셸 설정으로 해야, SSH 원격 접속 시에도 키 매핑이 어울리게끔 할 수 있는 것이다.

~/.inputrc 파일을 수정한다 (Bash가 아닌 다른 셸에서도 가능).

"\e[1;5C": forward-word
"\e[1;5D": backward-word

즉시 적용할 수 있다 (Bash 안에서만 수행).

bind -f ~/.inputrc

macOS 프로그램 (IDE 제외)

Homebrew 설치 이후 터미널에서 명령어를 입력한다.

Homebrew 설치

macOS의 필수 프로그램 1. (iTerm2도 HomeBrew로 설치할 것이기 때문.)

https://brew.sh/ko/

2023년에 확인했을 때는 zsh에서는 Homebrew 설치가 제대로 안 된다. 그래서 ~/.zshrc 파일을 수정한다.

export PATH=/opt/homebrew/bin:$PATH

https://stackoverflow.com/questions/36657321/after-installing-homebrew-i-get-zsh-command-not-found-brew

Homebrew cask 기능이 완전히 통합돼서, 2024년부터 brew tap homebrew/cask-versions 명령어가 불필요해진 것 같다.

iTerm2 (터미널) 설치

macOS의 필수 프로그램 2.

brew install --cask iterm2

설치 후 "macOS iTerm2 설정" 항목을 참고한다.

Thaw 설치

노치로 인해 좁아진 MacBook 메뉴 바 아이콘의 구원자 같은 프로그램이다. 원하는 아이콘만 보여주고, 숨길 아이콘을 선택할 수 있으며, 숨긴 아이콘을 따로 보는 것도 가능하다.

https://github.com/stonerl/Thaw

brew install thaw

"Launch at login" 설정은 필수다.

Karabiner Elements 설치

우측 Command를 한/영키로 바꾸기 위해서는 필요하다.

brew install --cask karabiner-elements

jenv 설치

# Install jenv
brew install jenv

.zshrc에 다음 내용을 추가한다.

# jenv
export PATH="$HOME/.jenv/bin:$PATH"
[ -x "$(command -v jenv)" ] && eval "$(jenv init -)"

OpenJDK 설치

JDK 11, 17, 21, 25를 설치하고, 17을 기본으로 사용한다.

Homebrew formula 중 openjdk는 symbolic link를 직접 걸어줘야 해서 불편하다...

특히 openjdk@8openjdk@8: The x86_64 architecture is required for this software. 오류가 나므로, 애플 실리콘 맥 기기에 설치할 수 없다. JDK 1.8의 경우에는 Zulu OpenJDK를 이용하자.

# Install Homebrew formulas
brew install openjdk@11 openjdk@17 openjdk@21 openjdk@25

# Symlink JDKs (required for Homebrew formulas not casks)
sudo ln -sfn /opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk \
    /Library/Java/JavaVirtualMachines/openjdk-11.jdk
sudo ln -sfn /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk \
    /Library/Java/JavaVirtualMachines/openjdk-17.jdk
sudo ln -sfn /opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk \
    /Library/Java/JavaVirtualMachines/openjdk-21.jdk
sudo ln -sfn /opt/homebrew/opt/openjdk@25/libexec/openjdk.jdk \
    /Library/Java/JavaVirtualMachines/openjdk-25.jdk

# List all JDKs
/usr/libexec/java_home -V

# Add JDKs to jenv
jenv add /Library/Java/JavaVirtualMachines/openjdk-11.jdk/Contents/Home
jenv add /Library/Java/JavaVirtualMachines/openjdk-17.jdk/Contents/Home
jenv add /Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home
jenv add /Library/Java/JavaVirtualMachines/openjdk-25.jdk/Contents/Home

# List all jenv JDKs
jenv versions

# Set Java 17.0 as default
jenv global 17.0

# Check current Java version
java -version

jenv 홈페이지가 깔끔하다.

https://www.jenv.be/

Rancher Desktop 설치

Apple Sillicon Mac 기기에서도 Docker나 Kubernetes를 가상 머신에서 실행시킬 수 있다.

https://rancherdesktop.io/

Homebrew로 설치하면 좀 다르다는 썰이 보이니, 그냥 홈페이지에서 설치 파일을 받는다.

GIMP 설치

brew install --cask gimp

(macOS) BetterTouchTool (유료)

https://folivora.ai/

외부 마우스 설정

Logitech 마우스가 아니라면, 이것으로 마우스 버튼을 mapping한다. Button 3 (좌측 위 버튼)은 "Move Left a Space", Button 4 (좌측 아래 버튼)은 "Move Right a Space"로 mapping한다.

키보드 설정

추가로 다음 단축키도 mapping한다.

  • control-J -> down (VIM 스타일)
  • control-K -> up (VIM 스타일)
  • fn+\ -> Toogle Bluetooth (블루투스 마우스 연결로 인해 트랙패드가 잠겼을 때 대응하는 수단)

(macOS) 구름 입력기

기존 macOS 입력기는 자꾸 이상한 유니코드 문자를 남긴다. 그리고 backtick - 원화 기호 설정 변경이 편하게 안 된다.

구름 입력기 설치

brew install --cask gureumkim

반드시 로그아웃을 한 번 해야 한다.

구름 입력기 설정

내부 단축키 설정

"한자 및 이모지 단축키"가 option-enter이므로, IntelliJ와 충돌한다.

단축키를 해제한다.

시스템 단축키 설정

"오른쪽 키로 언어 전환"을 해제한다. Karabiner Elements 방식보다 잘 씹힌다.

한글 입력기 설정

"한글 입력기일 때 역따옴표(`)로 원화 기호(\) 입력" 체크 상자를 해제한다.

"Esc 키로 로마자 자판으로 전환 (vi 모드)" 체크 상자를 설정한다.

우측 Command를 한/영키로 바꾸기

Karabiner Elements에서 right_command 등을 F16에 mapping한다.

https://makepluscode.tistory.com/164

하지만... 이 방식에는 문제가 있으니. 바로 UTM 같은 가상 머신 프로그램에서 오른쪽 커맨드 버튼이 전달되지 않는다는 것이다.

ChatGPT 3.5에게 다음 질문을 하여 Karabiner custom rule JSON을 생성했다.

"Give me a custom rule JSON for macOS Karabiner-Elements to map the right command key to F16 in any application except one of which bundle identifier is com.utmapp.UTM."

{
  "description": "Map right command key to F16 in any application except UTM",
  "manipulators": [
    {
      "type": "basic",
      "from": {
        "key_code": "right_command",
        "modifiers": {
          "optional": ["any"]
        }
      },
      "to": [{ "key_code": "f16" }],
      "conditions": [
        {
          "type": "frontmost_application_unless",
          "bundle_identifiers": ["com.utmapp.UTM"]
        }
      ]
    }
  ]
}

macOS 중요한 설정

(macOS 13 Ventura) Caps Lock으로 한/영 전환 하지 않도록 막기

환경설정 > 키보드 > 입력 소스 > 편집...

"한/영키로 key ABC 전환" 체크 상자를 해제한다.

(macOS 13 Ventura) 메뉴 바에 블루투스 아이콘 추가하기

https://www.iphonetricks.org/add-bluetooth-icon-to-menu-bar-macos-ventura/

키를 누르고 있을 때 '액센트가 있는 문자' 대신 키 반복 입력 사용하기

defaults write -g ApplePressAndHoldEnabled -bool false

https://macnews.tistory.com/2195

(macOS 13 Ventura) 키보드 입력 소스 설정 바꾸기

환경설정 > 키보드 > 입력 소스 > 편집...

맞춤법 자동 수정, 스페이스를 두 번 눌러 마침표 추가, 스마트 인용 부호 및 대시 사용 옵션을 모두 끈다.

큰따옴표와 작은따옴표를 곧은 것으로 고른다 (개발자 필수 옵션).

Mission Control 애니메이션 속도 올리기

Space(desktop) switching animation이 너무 느리다. 이건 꼭 필요하다.

defaults write com.apple.dock expose-animation-duration -float 0.1; killAll Finder && killAll Dock

https://apple.stackexchange.com/a/475279

텍스트 편집기(TextEdit) 기본 창 크기 설정하기

환경설정 (command-comma) > 윈도우 크기 section

너비 165자, 높이 60줄로 설정한다.

Function key (F1~F12)를 기본으로 사용하기

System Settings > Keyboard > Keyboard Shortcuts > Function Keys

https://apple.stackexchange.com/questions/450295/why-does-mac-running-ventura-os-now-insist-on-using-fn-key-to-deliver-function-k

트랙패드의 "페이지 쓸어넘기기" 제스처 설정하기

환경설정 > 트랙패드 > 추가 제스처 > 페이지 쓸어넘기기

이걸 "끔"에서 "두 손가락으로 좌우로 스크롤하기"로 바꿔야, Chrome에서 터치패드 두 손가락 좌우로 쓸기를 써서, 뒤로 가기와 앞으로 가기를 할 수 있다.

맥 화면 꺼짐 시 절전이 되지 않게 막기

https://letsgomin.com/2627/

# 전원 어댑터 연결 시 자동 절전 금지
sudo pmset -c sleep 0

# 배터리 사용 중에도 자동 절전 금지
sudo pmset -b sleep 0

(macOS) iTerm2 설정

Key

iTerm2 기본 키 설정만으로는 제대로 쓸 수가 없다. (오히려 macOS 기본 터미널 앱보다 더 불편할 수도 있다.)

Option(⌥) 키 안 먹히는 문제 고치기

iTerm2에서는 기본적으로 Zellij 같은 프로그램이 제대로 동작하지 않는다. 설정을 고쳐야, Option(⌥) 키가 전달되게 만들 수 있다. (사실 이 문제는 macOS 기본 터미널 앱에도 존재한다.)

Preferences > Profiles > Keys > General

"Left option (⌥) key"를 "Normal"에서 "Esc+"로 바꾼다.

임의의 전역 키 바인딩

나만의 키 바인딩이다.

참고로 Ignore라는 action은 터미널 내부로 키가 전달되지 않게 만든다.

내가 Previous Tab 주로 쓰는 키인 control-H는 Zellij와 충돌한다. ㅠㅠ 그런데 어차피 Cycle Tabs Forward/Backward 단축키인 control-(/shift)-tab이 있어서 쓸모가 없다.(?) 대체 왜 중복으로 존재하는 걸까?

  • (+): 기존 단축키에 추가한다.
  • (R): 기존 단축키를 제거하고 추가한다.
Action Default My binding
Previous Tab command-left (-) None
Next Tab command-right (-) None

프로필 키 바인딩 & Natural editing 키셋 설정

Preferences > Profiles > Keys > Key Bindings

"Presets..."에서 "Natural Text Editing"을 선택한다.

이걸 해야, command/option + arrow/delete 등의 조합을 사용할 수 있다.

https://superuser.com/a/1157575

하지만 Zellij를 잘 쓰려면, 여기서 또 option-leftoption-right binding들을 바꿔야 한다! alt-balt-f로 변환하는 설정이기 때문에, alt-f는 Zellij의 floating pane 기능과 충돌할 수밖에 없는 운명이다.

| Default | Key |
| :-- | :-- | :-- |
| Send Escape Sequence: Esc+[1;5D | option-left |
| Send Escape Sequence: Esc+[1;5C | option-right |

텍스트 선택 시 자동 복사 끄기

Preferences > General > Selection > Copy to pasteboard on selection (selection)

위 설정을 끈다.

글꼴 변경

Prefs > Profiles > Text > Font

  • 글꼴: D2Coding
  • 크기: 13

색상 조정

Prefs > Profiles > Colors

  • Basic Colors
    • Foreground: c7c7c7
    • Background: 000000
    • Brighten bold text: true
    • Minimum Contrast: 0
  • ANSI Colors:
    • Black Normal: 484848
    • Black Bright: 6b6b6b
    • Red Normal: c03a38
    • Red Bright: ef5350
    • Green Normal: 00cc33
    • Green Bright: 4eff79
    • Yellow Normal: ca9f02
    • Yellow Bright: fdcc1c
    • Blue Normal: 2072ac
    • Blue Bright: 3d99db
    • Magenta Normal: ab51ba
    • Magenta Bright: c792ea
    • Cyan Normal: 1e9094
    • Cyan Bright: 27b9be
    • White Normal: c7c7c7
    • White Bright: ffffff

색상 확인은 아래 Bash 스크립트로 한다.

#!/bin/bash
#
#   This file echoes a bunch of color codes to the
#   terminal to demonstrate what's available.  Each
#   line is the color code of one forground color,
#   out of 17 (default + 16 escapes), followed by a
#   test use of that color on all nine background
#   colors (default + 8 escapes).
#
#   Copied from http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html

T='gYw'   # The test text

echo -e "\n                 40m     41m     42m     43m\
     44m     45m     46m     47m";

for FGs in '    m' '   1m' '  30m' '1;30m' '  31m' '1;31m' '  32m' \
           '1;32m' '  33m' '1;33m' '  34m' '1;34m' '  35m' '1;35m' \
           '  36m' '1;36m' '  37m' '1;37m';
  do FG=${FGs// /}
  echo -en " $FGs \033[$FG  $T  "
  for BG in 40m 41m 42m 43m 44m 45m 46m 47m;
    do echo -en "$EINS \033[$FG\033[$BG  $T  \033[0m";
  done
  echo;
done
echo

기타 설정

Dimming 제거

Preferences > Appearance > Dimming

"Dim inactive split panes"를 해제함.

멀티 윈도우와 멀티 pane으로 놓고, 모두 한 번씩 볼 때가 있어서, 결국 투명한 흰색으로 덮는 dimming 기능은 꺼놓는 게 나음.

macOS 팁

글꼴 렌더링을 두껍게 만들기

레티나가 아닌 외부 모니터에서 글자를 더 잘 보이게 함. 재시작 필요!

https://qldhqldh.tistory.com/m/entry/맥-외부-모니터-가독성-증가

설정

defaults -currentHost write -g AppleFontSmoothing -int 2

해제

defaults -currentHost delete -g AppleFontSmoothing

(macOS 10.15 Catalina~) Root 디렉터리에 디렉터리 추가하기

https://apple.stackexchange.com/a/372500

Mission Control(control-up)에서 Spaces 재정렬 방지하기

시스템 환경설정 > 데스크탑 및 Dock > Mission Control

"Spaces를 최근 사용 내역에 따라 자동으로 재정렬" 체크 상자를 해제한다.

macOS 외부 마우스 쓰기

트랙패드와 애플 매직 마우스 대신 외부 마우스를 쓰려는 노력이다.

LinearMouse 설치

macOS의 마우스 설정은 매우 불편하고 끔찍하다. 마우스 smoothing과 scroll wheel smoothing을 없애려면 외부 프로그램 설치가 유일한 희망이다. (온라인에 있는 defaults 설정들은 죄다 가속도와 관계없는 그냥 속도 변경에 불과한 듯...)

brew install --cask linearmouse

https://github.com/lujjjh/LinearMouse

(macOS) BetterTouchTool 마우스 설정 (유료)

따로 나와 있는 BetterTouchTool 항목을 참고할 것.

Logitech 마우스라면, 마우스 설정에 대해서는 굳이 BetterTouchTool이 없어도 됨.

마우스 연결 시 트랙패드 끄기

환경설정 > 손쉬운 사용 > 포인터 제어기

"마우스 또는 무선 트랙패드가 있으면 내장 트랙패드 무시하기" 옵션을 활성화한다.

macOS 단축키 변경

macOS 설정 > 키보드 > 단축키

"사용 안 함"은 체크 상자를 해제하는 것이다.

Hierarchy Action Default My binding
Mission Control Mission Control control-up command-backtick
Mission Control 알림 센터 보기 없음 shift-command-backtick
키보드 다음 윈도우로 초점 이동 command-backtick 사용 안 함 (command-backtick)
서비스 텍스트 > 터미널에서 man 페이지 열기 shift-command-m 사용 안 함 (shift-command-m)
서비스 텍스트 > 터미널에서 man 페이지 인덱스 검색 shift-command-a 사용 안 함 (shift-command-a)

macOS 버그 해결

macOS Sequoia (15)부터 MS-DOS 볼륨 자동 마운트 방지 설정이 고장남

MSI 게이밍 모니터들은 MS-DOS 유형 볼륨(volume)에 대한 자동 마운트(auto-mount)가 일어나는데, 여태까지는 /etc/fstab 파일을 수정하여, 이 현상을 방지할 수 있었음.

macOS Sequoia (15)에서 이 설정이 고장나는 끔찍한 버그가 생겼고, 해결 방법이 한참 동안 미궁속에 빠져 있었으나, 아래와 같은 야매 버그 해결법을 찾아냄. (애플은 이 버그를 언제 고치나?)

https://discussions.apple.com/thread/255831146?answerId=255831146021&sortBy=rank#255831146021

Prior to my Sequoia upgrade, my working solution was the following fstab entry created using vifs:

    UUID={uuid from diskutil} none msdos rw,noauto

My solution was to change the filetype to from 'msdos' to 'auto'. This auto-detects the drive type.

    UUID={uuid from diskutil} none auto rw,noauto

macOS 상용 프로그램 문제 해결

Logi Options+ 완전 삭제

Logi Options+는 툭하면 무한 로딩에 걸리는 희대의 코드 뭉치 프로그램이다. 심지어 공식적으로는 문제 해결법이 전혀 없다. 유일한 해결 방법은 완전 삭제뿐인데, 이것도 제대로 알려주지 않는다.

https://www.reddit.com/r/logitech/comments/1q4fisd/comment/ny47hwn/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button

sudo /Library/Application\ Support/Logitech.localized/LogiOptionsPlus/logioptionsplus_agent.app/Contents/Frameworks/logioptionsplus_updater.app/Contents/MacOS/logioptionsplus_updater --full --uninstall

https://download01.logi.com/web/ftp/pub/techsupport/optionsplus/logioptionsplus_installer_1.44.415778.zip


Windows

Windhwak

필수 모드(mod)

m417z는 Windhwak 개발사인 Ramen Software의 일원이므로 신뢰할 수 있음.

  • m417z - Better file sizes in Explorer details - explorer-details-better-file-sizes
  • m417z - Cycle taskbar buttons with mouse wheel - taskbar-wheel-style
    • 단축키 Win-[ & Win-]을 사용할 수 있음. Logi Options+에서 각각을 앞으로 버튼, 뒤로 버튼에 할당해야 함.
    • Taskbar Volume Control (taskbar-volume-control)과 기능이 겹치므로, "Enable mouse wheel cycling" 설정은 해제하는 게 좋음. (어차피 우선권을 뺏기긴 함.)
  • m417z - Taskbar Volume Control - taskbar-volume-control

Node.JS

NVM 및 Node.JS 설치

VS Code의 확장 기능에서 Node.JS에 의존하는 경우가 많다. 그래서 NVM과 Node.JS를 먼저 설치한다.

macOS

https://yarisong.tistory.com/44

brew install nvm
mkdir -p ~/.nvm

~/.zshrc를 수정한다.

export NVM_DIR=~/.nvm
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"

터미널을 다시 열고, 사용 가능한 Node.JS 버전을 확인한다.

# Check Node.JS versions
nvm ls-remote

적당한 LTS 버전을 설치하고, 해당 버전을 기본으로 설정한다. (나온 지 얼마 안 된 LTS 버전은 호환성 문제가 생길 수 있다.)

# Install Node.JS
nvm install v24

# Set default version of Node.JS
# (Not required after first Node.JS installation)
nvm alias default v24

# List installed Node.JS versions
nvm ls

# Check current Node.JS runtime version
node -v

전역 모듈 설치

VS Code 확장을 위한 모듈들

npm install -g prettier eslint typescript

ESLint의 플러그인 모듈들

npm install -g eslint-plugin-react eslint-plugin-prettier eslint-plugin-react-hooks

Rust & Cargo

Rust 설치

macOS

brew install rust

셸 환경 설정

.zshrc 또는 .bash_profile에 추가돼 있어야 함.

# Cargo
export PATH="$HOME/.cargo/bin:$PATH"

유용한 CLI 프로그램

어느 OS에서든 설치하기 쉬운 CLI 프로그램들임.

일반

bat

cat과 비슷한 용도. Rust로 개발됨.

https://github.com/sharkdp/bat

dust

du와 비슷한 용도. Rust로 개발됨.

https://github.com/bootandy/dust

fzf

fzf is a general-purpose command-line fuzzy finder. Go로 개발됨.

https://github.com/junegunn/fzf

Shell integration 있음. Intruction대로 진행해야 함.

# .zshrc
source <(fzf --zsh)

# .bash_profile
eval "$(fzf --bash)"

Zellij

친절한 인터페이스가 아주 훌륭한 terminal multiplexer 프로그램임. Rust로 개발됨.

설치 방법:

나만의 설정:

Git 강화

이 항목에서 GitHub을 위한 CLI 프로그램은 다루지 않음. ghqgwq는 필수임.

ghq

Git 저장소 디렉터리를 정돈된 디렉터리로 복제해줌.

https://github.com/x-motemen/ghq

디렉터리는 ~/ghq/<domain>/<owner>/<repo>/임.

gwq

Git worktree manager 중 하나.

https://github.com/d-kuro/gwq

Shell completion 설정이 필요하므로 주의.

설정이 복잡하므로, 별도의 항목에서 추가로 정리함.

협업 솔루션

주로 AI 에이전트를 부려먹기 위해 필요한 CLI 프로그램들임.

gh

GitHub 또는 GHES를 위한 공식 CLI 프로그램.

설치 방법:

pchuri Confluence CLI

Confluence wiki를 위한 비공식 CLI 프로그램.

https://github.com/pchuri/confluence-cli

Altanssian 솔루션 체크리스트:

  • Cloud 배포판 지원 여부: Y
  • Server / Data Center 배포판 지원 여부: Y (PAT w. bearer auth)

설치 방법:

npm install -g confluence-cli

Claude Code 플러그인 추가 (Claude Code 명령)

/plugin marketplace add pchuri/confluence-cli
/plugin install confluence@pchuri-confluence-cli

pchuri Jira CLI

Jira를 위한 비공식 CLI 프로그램.

https://github.com/pchuri/jira-cli

Altanssian 솔루션 체크리스트:

  • Cloud 배포판 지원 여부: Y
  • Server / Data Center 배포판 지원 여부: Y (PAT w. bearer auth)

설치 방법:

npm install -g @pchuri/jira-cli

Claude Code 스킬 추가 (명령행):

jira install-skill --force --dest ~/.claude/skills/jira

gwq 전역 설정

전역 설정 파일은 ~/.config/gwq/config.toml임.

기본 전역 설정

기본 디렉터리는 ~/worktrees/<domain>/<owner>/<repo>/<branch>/임. 브랜치 이름에서 특정 특수문자들(/, :)은 대시(-)로 대체됨.

내 디렉터리는 ~/ghq/<domain>/<owner>/<repo>[worktree]/[<repo>]<branch>/임.

이를 위해, 전역 설정 파일 앞부분을 이렇게 바꿈. 에디터 창 이름을 직관적으로 만들기 위한 조치임.

[finder]
preview = true

[naming]
template = '{{.Host}}/{{.Owner}}/{{.Repository}}[worktree]/[{{.Repository}}]{{.Branch}}'

[naming.sanitize_chars]
'/' = '_'
':' = '-'

[ui]
icons = true
tilde_home = true

[worktree]
auto_mkdir = true
basedir = '~/ghq'

[[repository_settings]] 항목들은 며느리에게도 알려줄 수 없는 비밀이므로 생략함. Repo마다 (.gwq.toml을 놓는 것도 고려해 봐야겠음.)

저장소 설정

Claude Code를 사용한다는 가정으로 아래와 같이 여러 개를 추가함.

<repo-dir>에 기본 저장소 디렉터리를 넣은 설정을 만들면 됨. (당연히 기본 저장소 디렉터리는 worktree 디렉터리가 아니라, 평범하게 git clone을 한 것임.)

[[repository_settings]]
repository = "<repo-dir>"
copy_files = [
    ".claude/settings.local.json",
    "CLAUDE.local.md"
]
setup_commands = [
    # ...
]

저장소 간단한 셋업 명령어

Git 하위 모듈 초기화

Git 하위 모듈을 쓰는 프로젝트에는 필수다.

"git submodule update --init --recursive"

저장소 복잡한 셋업 스크립트

Gradle 프로젝트 전용 build 디렉터리 복사 스크립트

Gradle 초기 빌드 속도를 조금이나마 올려보려는 노력임. ㅠㅠ

아래처럼 셸 스크립트를 만듦.

mkdir -p ~/my-scripts/worktree/



cat <<'EOF' > ~/my-scripts/worktree/gradle-project-setup.sh
#!/usr/bin/env bash

set -euo pipefail

src="${1:?Usage: gradle-project-setup.sh <original-dir>}"
dst="$(pwd)"

copied=0
start_time=$(date +%s)

copy_dir() {
    local from="$1" to="$2" label="$3"
    local size t_start t_end elapsed
    if du --version 2>/dev/null | grep -q GNU; then
        size=$(du -sh --exclude='build' "$from" 2>/dev/null | cut -f1)
    else
        size=$(du -sh -I build "$from" 2>/dev/null | cut -f1)
    fi
    t_start=$(date +%s)
    rsync -a "$from/" "$to/"
    t_end=$(date +%s)
    elapsed=$((t_end - t_start))
    printf "[copy] %s (%s, %ds)\n" "$label" "$size" "$elapsed"
    copied=$((copied + 1))
}

if [ -d "$src/.vscode" ]; then
    copy_dir "$src/.vscode" "$dst/.vscode" ".vscode"
fi

if [ -d "$src/.idea" ]; then
    copy_dir "$src/.idea" "$dst/.idea" ".idea"
fi

total_elapsed=$(( $(date +%s) - start_time ))
printf "Done. %d directories copied in %ds.\n" "$copied" "$total_elapsed"
EOF



chmod +x ~/my-scripts/worktree/gradle-project-setup.sh

gwq 버전 0.0.13 기준으로 셋업 명령어 해석 로직에 명령어 토큰 분할 버그가 있음. (그냥 스페이스로 잘라버림;) 따라서 bash -c를 못 쓰므로, 절대 경로를 써야 함.

[[repository_settings]]
repository = "<repo-dir>"
setup_commands = [
    "<absolute-home-dir>/my-scripts/worktree/gradle-project-setup.sh <absolute-repo-dir>'"
]

IntelliJ IDEA Community

IntelliJ 설치 (OS 공통)

JetBrains Toolbox를 이용해 설치한다.

https://www.jetbrains.com/toolbox-app/

현재 기준으로 IntelliJ IDEA Community 2025.1을 설치한다. 당연히 New UI가 기본이다.

IntelliJ 주의할 점

인코딩

Editor > File Encodings

인코딩 (UTF-8) 설정은 프로젝트별로 모두 필요하다. 최신 버전에서는 전역 설정도 생겨서 좋아졌다.

Run/debug 구성 이사하기

각 프로젝트의 run/debug configuration은 아직까지도 쉽게 이사하는 방법이 없다 (.run 디렉터리 XML 파일을 유지하고 싶지 않다면...). 즉 import/export 기능이 전무하다. 하나하나 share 체크를 한 후, .run 디렉터리 XML 파일을 만들어서 노가다로 옮기고, 옮긴 뒤에 share 체크를 하나하나 다시 푼다.

https://stackoverflow.com/a/24642246

그 다음으로 좋은 방법은 Gradle이나 Maven에서 clean task를 한 번 수행한 다음, .gradle 디렉터리를 제외한 모든 파일을 압축해서 옮기는 것이다. 정신 건강에 아주 이롭다고 할 수 있겠다.(...)

IntelliJ preferences

편집기 글꼴

Editor > Font

  • Font: D2Coding
  • Size: 16.0
  • Line spacing: 1.21

파일 끝에 줄바꿈 문자 넣기

Editor > General > On Save (section)

"Ensure envery saved file ends with a line break" 체크 상자를 설정한다.

줄바꿈 문자 화면에 표시하기

Editor > Genereal > Appearance

"Show whitespaces" 체크 상자를 설정한다. "Inner"를 제외하고, "Leading", "Trailing", "Selection" 체크 상자를 설정한다.

IntelliJ indent guide 보기

Editor > Genereal > Appearance

"Show indent guides" 체크 상자를 설정한다. (최신 버전에서는 기본인 듯하다.)

한 줄 메서드가 접히지 않게 하기

Editor > Genereal > Code Folding > Java (section)

"One-line methods" 체크 상자를 해제한다.

IntelliJ editor tab 위쪽 대신 오른쪽에 놓기

Editor > General > Editor Tabs > Apprearance (section)

"Tab placement" 선택 상자를 "Right"로 지정한다.

Editor > General > Editor Tabs > Closing Policy (section)

덤으로 탭 개수 제한도 풀면 좋다. "Tab limit"을 20으로 조정한다.

Breadcrumbs 사용하기

Editor > General > Breadcrumbs

"Show breadcrumbs" 체크 상자를 설정하고 (최신 버전에서는 기본인 듯하다.), "Placement"를 Top으로 한다.

"Languages"에서 "Java"와 "Kotlin" 체크 상자를 설정한다.

Smooth scrolling 끄기

Appearance & Behavior > Appearance > UI Options

"Smoothing scrolling" 체크 상자를 해제한다.

IntelliJ 단축키 설정

Keymap

VIM style (HJKL)이 어느 정도 가미되었다. 그리고 IntelliJ로 VCS를 조작하지 않고, 터미널에서 Git을 조작하기 때문에, 관련 단축키는 무시했다.

macOS

IntelliJ preference에서 "Keymap"으로 가서 프로필을 "macOS"로 맞춘 다음, "Duplicate..."를 눌러 복제한다.

macOS 기본 단축키와 충돌하면 답이 없는 경우가 있으므로 꼭 확인해야 한다.
https://support.apple.com/ko-kr/HT201236

  • (+): 기존 단축키에 추가한다.
  • (R): 기존 단축키를 제거하고 추가한다.
  • "Run", "Debug"는 자주 쓰는 VIM 단축키와 충돌하므로 바꾸었다.
  • "Code Completion"의 "Basic"은 macOS 시스템 단축키와 충돌하므로 바꾸었다.
Menu hierarchy Action Default My binding
Editor Actions Down down (+) control-J
Editor Actions Extend Selection option-up (+) option-K
Editor Actions Shrink Selection option-down (+) option-J
Editor Actions Scroll to Top None (+) command-up
Editor Actions Scroll to Bottom None (+) command-down
Editor Actions Up up (+) control-K
Main menu > Edit > Find Replace... command-R (R) option-command-F
Main menu > Edit > Find Find in Files... shift-command-F (R) control-option-F
Main menu > Edit > Find Replace in Files... shift-command-R (R) control-option-command-F
Main menu > Edit > Find Find Usages option-F7 (+) command-U
Main menu > Code > Code Completion Basic control-space (R) control-option-space
Main menu > Code Reformat Code option-command-L (R) shift-command-F
Main menu > Code Reformat File... option-shift-command-L (R) control-shift-command-F
Main menu > Code Move Line Up/Down option-shift-up/down (+) option-shift-K/J
Main menu > Navigate Back/Forward option-command-left/right (+) control-option-H/L (Remove mouse clicks)
Main menu > Navigate > Goto by Reference Actions Go to Super Method command-U (R) control-command-U
Main menu > Navigate > Goto by Reference Actions Go to Test shift-command-T (R) control-T
Main menu > Navigate > Hierarchy Actions Type Hierarchy control-H (R) command-T command-T
Main menu > Navigate > Hierarchy Actions Method Hierarchy shift-command-H (R) command-T command-F
Main menu > Navigate > Hierarchy Actions Call Hierarchy control-option-H (R) command-T command-C
Main menu > Navigate > Navigate in File Previous/Next Method control-up/down (+) control-option-K/J
Main menu > Refactor Refactor This... control-T (R) control-command-R
Main menu > Refactor Rename... shift-F6 (+) shift-command-R
Main menu > Run Run... control-option-R (R) control-option-X
Main menu > Run Debug... control-option-D (R) control-option-G
Main menu > Run > Run/Debug Run control-R (R) control-X
Main menu > Run > Run/Debug Debug control-D (R) control-G
Main menu > Window > Editor Tabs Reopen Closed Tab None (+) shift-command-T
Main menu > Window > Editor Tabs Split Right None (+) command-\
Main menu > Window > Editor Tabs Select Previous/Next Tab control-left/right (R) control-H/L
Main menu > Window > Editor Tabs Goto Previous/Next Splitter option-(/shift)+right (+) control-shift-H/L
Main menu > Window > Editor Tabs Goto Move option-(/shift)-right (+) control-shift-H/L
Other Activate Previous/Next Window (/shift)-command-backtick (R) control-option-command-H/L

IntelliJ Plugins

  • IdeaVim
  • GitHub Copilot
  • TabMover by Miklos Jakab

IntelliJ GitHub Copilot Plugin

IDE 기준 버전: IntelliJ IDEA 2025.1

IDE 자동 완성 충돌 방지

Tools > GitHub Copilot > Completions

"Show IDE completions side-by-side"의 체크 상자를 설정한다. 기본적으로는 해제돼 있다.

(2025년 7월 기준) 이 설정을 꼭 활성화해야 IntelliJ의 자동 완성 (패턴 및 기계 학습)이 Copilot의 자동 완성 (LLM AI)을 씹는 일을 막을 수 있다. 이 설정을 켜면 동시에 두 가지 자동 완성을 모두 볼 수 있으며 (아래에 있는 줄들이 가려지긴 함), Tab 키를 누르면 Copilot 자동 완성이 동작하고, Enter 키를 누르면 IntelliJ 자동 완성이 동작한다.

사실 VS Code로 개발할 때는 IDE 자동 완성이 그렇게 큰 도움이 되지 않다 보니 Copilot을 우선으로 해도 괜찮다. 하지만 JVM 언어는 대부분 강타입 언어이기 때문에, IntelliJ에서는 IDE 자동 완성이 Copilot보다 더 유용할 때가 많은 것 같다.

TabMover

Keymap을 조정해야 한다.

Menu hierarchy Action Default My binding
Plugins > TabMover Move Tab to Previous/Next option-shift-command-left/right (+) control-command-L/H

IntelliJ Theme

설치

Plugin으로 "Night Owl Native" by Aradi Patrik을 설치해야 한다.

https://plugins.jetbrains.com/plugin/13448-night-owl-native

"Rainbow Brackets Lite"도 설치한다. VS Code와 다르게, bracket 종류에 상관없는 색깔 순환이 이뤄지지 않으므로, round brackets만 적용할 것이다.

https://plugins.jetbrains.com/plugin/20710-rainbow-brackets-lite

Color Scheme 조정

Java와 Kotlin 위주로 조정한다.

IntelliJ preference에서 "Editor > Color Scheme"으로 가서 "Scheme"을 "one-dark-native"로 맞춘 다음, "Duplicate..."를 눌러 복제한다.

터미널 글꼴 설정

Editor > Color Scheme > Console Font

  • Font: D2Coding
  • Size: 15.0
  • Line spacing: 1.10

상세

macOS의 VS Code는 IntelliJ보다 실제 색깔이 덜 붉게 나오기 때문에, IntelliJ에서는 인스턴스 필드 이름 색깔을 7FDBCA 대신 88D3C3으로 쓴다. 그래야 비슷해진다. (95DBCA 쓰다가 88D3C3으로 바꿈.)

나중에 배경 색깔이 더 필요해지면, 3F001F (어두운 초록색)을 사용할 예정.

Menu hierarchy Section hierarchy Changes
General Code > TODO defaults fg: FFEB95 -ErrorStripeMark -Italic
General Errors and Warnings > Error -fg -bg +Effects: B71C1C underwaved
General Errors and Warnings > Warning -fg -bg +Effects: EF7F17 underwaved
General Errors and Warnings > Weak Warning -fg -bg +Effects: 3F9F4F underwaved
General Text > Folded text fg: F3F349 bg: 0A415B
General Text > Whitespaces fg: 174F7F
Language Defaults Braces and Operators > Brackets fg: C792EA
Language Defaults Braces and Operators > Brackets fg: C792EA
Language Defaults Braces and Operators > Comma -fg
Language Defaults Braces and Operators > Dot fg: C792EA
Language Defaults Braces and Operators > Parentheses fg: 89DDF7
Language Defaults Braces and Operators > Semicolon fg: 89DDF7
Language Defaults Classes > Class name fg: ADDB67
Language Defaults Classes > Instance field fg: 88D3C3 -Inherit
Language Defaults Classes > Interface name fg: 35C37F
Language Defaults Classes > Static field fg: 88D3C3 +Italic
Language Defaults Classes > Static method fg: 82AAFF +Italic
Language Defaults Identifiers > Default fg: D6DEEB -bg -Inherit
Language Defaults Identifiers > Function declaration fg: 82AAFF -Italic
Language Defaults Identifiers > Label fg: 2F4FFF -Inherit
Language Defaults Identifiers > Local variable +Inherit
Language Defaults Identifiers > Parameter +Inherit
Language Defaults Inline hints > Default fg: 707084 bg: 3B3B3B
Language Defaults Inline hints > Parameters > Current fg: D6DEEB bg: 7E57C2
Language Defaults Inline hints > Parameters > Default fg: 1A7C7F bg: 3B3B3B
Language Defaults Inline hints > Parameters > Highlighted fg: 20999D bg: 646464
Language Defaults Inline hints > Text without background fg: 707084
Language Defaults Keyword fg: C792EA -Italic
Language Defaults Markup > Attribute fg: 82AAFF -Inherit
Language Defaults Metadata fg: AB51BA -Inherit
Language Defaults String > Escape Sequence > Invalid fg: B71C1C Effects: B71C1C underwaved
Language Defaults String > Escape Sequence > Valid fg: F36D75
Console Colors ANSI Colors > Black fg: 484848 bg:same
Console Colors ANSI Colors > Blue fg: 2072AC bg:same
Console Colors ANSI Colors > Bright Black fg: 6B6B6B bg:same
Console Colors ANSI Colors > Bright Blue fg: 3D99DB bg:same
Console Colors ANSI Colors > Bright Cyan fg: 27B9BE bg:same
Console Colors ANSI Colors > Bright Green fg: 4EFF79 bg:same
Console Colors ANSI Colors > Bright Magenta fg: C792EA bg:same
Console Colors ANSI Colors > Bright Red fg: EF5350 bg:same
Console Colors ANSI Colors > Bright White fg: FFFFFF bg:same
Console Colors ANSI Colors > Bright Yellow fg: FDCC1C bg:same
Console Colors ANSI Colors > Cyan fg: 1E9094 bg:same
Console Colors ANSI Colors > Green fg: 00CC33 bg:same
Console Colors ANSI Colors > Magenta fg: AB51BA bg:same
Console Colors ANSI Colors > Red fg: C03A38 bg:same
Console Colors ANSI Colors > White (Gray) fg: C7C7C7 bg:same
Console Colors ANSI Colors > Yellow fg: CA9F02 bg:same
Console Colors Console > Standard output fg: C7C7C7
Console Colors Console > System output fg: C7C7C7
Java Annotations > Annotation attribute name fg: 20999D
Java Annotations > Annotation name +Inherit
Java Classes and Interfaces > Abstract Class +Inherit
Java Classes and Interfaces > Class +Inherit
Java Classes and Interfaces > Interface +Inherit
Java Methods > Constructor call fg: ADDB67 -Inherit
Java Methods > Method Call +Inherit
Java Methods > Static Method +Inherit
Java Parameters > Implicit anonymous class parameter -fg bg: 2F2F0F -Effects
Java Parameters > Type parameter fg: 20999D
JSON Property key fg: C5E478 -Inherit
JSON String +Inherit
Groovy Classes and Interfaces > Class +Inherit
Groovy Methods > Static method call +Inherit
Groovy Map key/Named argument fg: 20999D -Inherit
Groovy Methods > Method declaration +Inherit
Groovy References > Static property reference +Inherit
Kotlin Braces and Operators > Arrow -fg -Inherit
Kotlin Braces and Operators > Non-null assertion fg: FF5370
Kotlin Braces and Operators > Operator sign +Inherit
Kotlin Classes and Interfaces > Enum entry fg: F78C6C -Italic -Inherit
Kotlin Classes and Interfaces > Object fg: ADDB67 +Italic -Inherit
Kotlin Functions > Constructor call fg: ADDB67 -Inherit
Kotlin Functions > Package-level function call +Inherit
Kotlin Label +Inherit
Kotlin Named argument fg: 20999D
Kotlin Parameters > Lambda expression default parameter fg: FFFFFF +Bold
Kotlin Parameters > Type parameter +Inherit
Kotlin Properties and Variables > Backing field variable fg: C792EA -Bold
Kotlin Properties and Variables > Dynamic property fg: ADDB67 -Bold -Italic
Kotlin Properties and Variables > Extension property fg: 53BDEC +Italic -Inherit
Kotlin Properties and Variables > Synthetic extension ... fg: 53BDEC -Italic -Inherit
Kotlin Properties and Variables > ... captured in closure -fg bg: 2F2F0F -Inherit
Kotlin Smart-casts > Smart-cast implicit receiver -fg bg: 3F001F
Kotlin Smart-casts > Smart-cast value -fg bg: 3F001F
Kotlin Smart-casts > Smart constant -fg bg: 3F001F
Properties Invalid unicode code points +Inherit
Properties Key/value separator fg: C792EA
Properties Property key fg: C5E478
Properties Valid string escape +Inherit
XML Attribute name +Inherit
XML Tag fg: C792EA -bg -Inherit
XML Tag Data +Inherit
XML Tag Name fg: C5E478
XML Prologue fg: C792EA -bg -Inherit
YAML Key fg: C5E478 -Inherit
YAML Text fg: ECC48D -bg -Inherit
Rainbow Brackets Lite Round Brackets - Color #1 89DDF7
Rainbow Brackets Lite Round Brackets - Color #2 B3A03F
Rainbow Brackets Lite Round Brackets - Color #3 08916A
Rainbow Brackets Lite Round Brackets - Color #4 DF878F
Rainbow Brackets Lite Round Brackets - Color #5 2F9FC3

Visual Studio Code (VS Code)

VS Code 설치

macOS

brew install --cask visual-studio-code

VS Code extensions

Common

NodeJS 관련 확장의 경우, NPM을 통해 필요한 모듈들을 전역에 먼저 설치한다.

  • EditorConfig for VS Code (editorconfig.editorconfig)
  • GitLens — Git supercharged (eamodio.gitlens)
  • Multiple Formatters (Jota0222.multi-formatter)
  • Vim (vscodevim.vim)

Language

프로그래밍 언어 또는 마크업 언어를 정적으로 분석하는 확장임. ESLint 말고는 Microsoft 공식 확장을 제외함.

  • Markdown
    • Markdown All in One (yzhang.markdown-all-in-one)
    • Markdown Extended (jebbs.markdown-extended)
    • Markdown Preview GitHub Styling (bierner.markdown-preview-github-styles)
    • Markdown table from CSV/TSV (jojoco.markdownfromcsv)
  • JavaScript/TypeScript/JSON
    • ESLint (dbaeumer.vscode-eslint)
    • Prettier - Code formatter (esbenp.prettier-vscode)
  • Miscellaneous non-markup
    • Kotlin (fwcd.kotlin)
    • SQL Formatter (adpyke.vscode-sql-formatter)
  • Miscellaneous markup
    • XML (redhat.vscode-xml)
    • TOML
      • Even Better TOML (tamasfe.even-better-toml)

다음 확장은 예외적으로 기록했다.

  • Python
    • Black Formatter (ms-python.black-formatter)
      • Python formatting에 필요하나, VS Code가 추천해주지 않음...

JS/TS framework

  • Frontend big framework
    • Svelte for VS Code (svelte.svelte-vscode)
  • Styling
    • UnoCSS (antfu.unocss)
  • Components
    • shadcn/svelte (Selemondev.vscode-shadcn-svelte)

JSON

  • JSON Tools (eriklynd.json-tools)
  • Sort JSON objects (richie5um2.vscode-sort-json)

Theme

  • Night Owl (sdras.night-owl)

Utils

편의성 기능들임.

  • Bookmarks (alefragnani.Bookmarks)
  • Escape HTML code (raymondcamden.htmlescape-vscode-extension)
  • Escape-quotes (milovidov.escape-quotes)
  • Go to Next/Previous Member (mishkinf.goto-next-previous-member)
  • Quit Control for VSCode (artdiniz.quitcontrol-vscode)
  • URL Encode (flesler.url-encode)

VS Code settings.json

macOS 기준이므로, VIM 키 바인딩 충돌 설정은 뺐음.

{
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Claude Code                                                              ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  "claudeCode.hideOnboarding": true,
  "claudeCode.preferredLocation": "sidebar",
  "claudeCode.selectedModel": "default",
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Common settings                                                          ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  "breadcrumbs.enabled": true,
  "chat.agent.enabled": false,
  "chat.disableAIFeatures": true,
  "chat.viewSessions.orientation": "stacked",
  "diffEditor.ignoreTrimWhitespace": false,
  "editor.bracketPairColorization.enabled": true,
  "editor.fontFamily": "D2Coding, Menlo, Monaco, 'Courier New', monospace",
  "editor.fontSize": 16,
  "editor.quickSuggestions": {
    "other": "on",
    "comments": "off",
    "strings": "on"
  },
  "editor.suggestSelection": "first",
  "editor.renderFinalNewline": "on",
  "editor.renderWhitespace": "boundary",
  "editor.rulers": [100],
  "extensions.ignoreRecommendations": false,
  "git.mergeEditor": false,
  "git.openRepositoryInParentFolders": "never",
  "html.format.unformatted": "li, p, wbr",
  "scm.repositories.selectionMode": "single",
  "terminal.integrated.defaultProfile.osx": "zsh-login",
  "terminal.integrated.fontSize": 14,
  "terminal.integrated.inheritEnv": true,
  "terminal.integrated.lineHeight": 1.072,
  "terminal.integrated.minimumContrastRatio": 1.2,
  "terminal.integrated.profiles.osx": {
    "zsh-login": {
      "path": "zsh",
      // Use login shell
      // https://github.com/Microsoft/vscode/issues/20265#issuecomment-278818467
      "args": ["-l"]
    }
  },
  "terminal.integrated.stickyScroll.enabled": false,
  "window.title": "VC${separator}${rootName}",
  "workbench.colorTheme": "Night Owl (No Italics)",
  "workbench.editor.decorations.colors": true,
  "workbench.editor.showTabs": "multiple",
  "workbench.editor.wrapTabs": true,
  "workbench.editorAssociations": {
    "*.ipynb": "jupyter-notebook"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Extension (non-language) settings                                        ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  "docker.extension.dockerEngineAvailabilityPrompt": false,
  "gitlens.codeLens.enabled": false,
  "gitlens.plusFeatures.enabled": false,
  "gitlens.terminal.overrideGitEditor": false,
  "gitlens.views.branches.branches.layout": "list",
  "gitlens.views.searchAndCompare.files.icon": "status",
  "gitlens.views.scm.grouped.views": {
    "commits": true,
    "branches": true,
    "remotes": true,
    "stashes": true,
    "tags": true,
    "worktrees": true,
    "contributors": true,
    "fileHistory": false,
    "repositories": true,
    "searchAndCompare": true,
    "launchpad": false
  },
  "redhat.telemetry.enabled": false,
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Extension (language) settings                                            ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  "black-formatter.args": ["--line-length", "99", "--skip-string-normalization"],
  "python.analysis.typeCheckingMode": "standard",
  "eslint.format.enable": true,
  "eslint.trace.server": "messages",
  // By default, ESLint VS Code Plugin validates JS only.
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact",
    "html",
    "svelte",
    "vue"
  ],
  "kotlin.debugAdapter.enabled": false,
  "kotlin.diagnostics.enabled": false,
  "kotlin.indexing.enabled": false,
  "kotlin.languageServer.enabled": false,
  "markdown.editor.filePaste.copyIntoWorkspace": "never",
  "markdown.extension.toc.updateOnSave": false,
  "markdown-pdf.displayHeaderFooter": false,
  // Markdown PDF uses `https://unpkg.com/mermaid/dist/mermaid.min.js`, which is broken now.
  // https://github.com/yzane/vscode-markdown-pdf/issues/312
  "markdown-pdf.mermaidServer": "https://unpkg.com/mermaid@11.9.0/dist/mermaid.min.js",
  "markdown-preview-github-styles.darkTheme": "dark_dimmed",
  "prettier.printWidth": 100,
  "prettier.singleQuote": true,
  "prettier.trailingComma": "all",
  "svelte.enable-ts-plugin": true,
  "typescript.updateImportsOnFileMove.enabled": "never",
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ File extension settings                                                  ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  "[Compose]": {
    "editor.defaultFormatter": "docker.docker"
  },
  "[css]": {
    "editor.defaultFormatter": "vscode.css-language-features",
    "editor.formatOnSave": true,
    "files.insertFinalNewline": true
  },
  "[dockercompose]": {
    "editor.defaultFormatter": "docker.docker"
  },
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "multiFormatter.formatterList": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
  },
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "multiFormatter.formatterList": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "multiFormatter.formatterList": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[markdown]": {
    "editor.quickSuggestions": {
      "comments": "off",
      "strings": "off",
      "other": "off"
    },
    "editor.wordWrap": "on",
    "editor.defaultFormatter": "yzhang.markdown-all-in-one"
  },
  "[python]": {
    "editor.formatOnType": true,
    "editor.defaultFormatter": "ms-python.black-formatter"
  },
  "[scss]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  },
  "[svelte]": {
    "editor.defaultFormatter": "svelte.svelte-vscode",
    "multiFormatter.formatterList": [
      // Svelte VS Code Plugin formatter includes Prettier by default.
      "svelte.svelte-vscode",
      // Donno why, but this is not working now. Have no option other than running "Format Document
      // With..." > "ESLint".
      "dbaeumer.vscode-eslint"
    ]
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "multiFormatter.formatterList": [
      "esbenp.prettier-vscode",
      "dbaeumer.vscode-eslint",
      "vscode.typescript-language-features"
    ]
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "multiFormatter.formatterList": [
      "esbenp.prettier-vscode",
      "dbaeumer.vscode-eslint",
      "vscode.typescript-language-features"
    ]
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Theme customization                                                      ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Original: https://github.com/sdras/night-owl-vscode-theme/blob/main/themes/Night%20Owl-color-theme-noitalic.json
  "workbench.colorCustomizations": {
    "editorBracketHighlight.foreground1": "#89DDF7",
    "editorBracketHighlight.foreground2": "#B3A03F",
    "editorBracketHighlight.foreground3": "#08916A",
    "editorBracketHighlight.foreground4": "#DF878F",
    "editorBracketHighlight.foreground5": "#2F9FC3",
    // // [Dark background start]
    // "editorHoverWidget.background": "#161616",
    // "editor.background": "#161616",
    // "editorGutter.background": "#161616",
    // "panel.background": "#161616",
    // "statusBar.background": "#161616",
    // "terminal.background": "#161616",
    // // [Dark background end]
    // // [GitHub dimmed background start]
    // "editorHoverWidget.background": "#22272e",
    // "editor.background": "#22272e",
    // "editorGutter.background": "#22272e",
    // "panel.background": "#22272e",
    // "statusBar.background": "#22272e",
    // "terminal.background": "#22272e",
    // // [GitHub dimmed background end]
    "terminal.foreground": "#C7C7C7",
    "terminal.ansiBlack": "#484848",
    "terminal.ansiBrightBlack": "#6B6B6B",
    "terminal.ansiBlue": "#2072AC",
    "terminal.ansiBrightBlue": "#3D99DB",
    "terminal.ansiCyan": "#1E9094",
    "terminal.ansiBrightCyan": "#27B9BE",
    "terminal.ansiGreen": "#00CC33",
    "terminal.ansiBrightGreen": "#4EFF79",
    "terminal.ansiMagenta": "#AB51BA",
    "terminal.ansiBrightMagenta": "#C792EA",
    "terminal.ansiRed": "#C03A38",
    "terminal.ansiBrightRed": "#EF5350",
    "terminal.ansiWhite": "#C7C7C7",
    "terminal.ansiBrightWhite": "#FFFFFF",
    "terminal.ansiYellow": "#CA9F02",
    "terminal.ansiBrightYellow": "#FDCC1C"
  },
  "editor.tokenColorCustomizations": {
    "[Night Owl (No Italics)]": {
      "variables": "#D6DEEB",
      "textMateRules": [
        {
          "name": "Keyword Operator",
          "scope": "keyword.operator",
          "settings": {
            "foreground": "#C792EA"
          }
        },
        {
          "name": "Keyword",
          "scope": [
            "constant.language",
            "constant.language.boolean",
            "constant.language.null",
            "variable.language.this",
            "keyword.operator.new",
            "meta.method.declaration storage.type"
          ],
          "settings": {
            "foreground": "#C792EA"
          }
        },
        {
          "name": "Single or double quote character",
          "scope": ["punctuation.definition.string"],
          "settings": {
            "foreground": "#ecc48d"
          }
        },
        {
          "name": "Constant Character Escape",
          "scope": ["constant.character.escape"],
          "settings": {
            "foreground": "#F36D75"
          }
        },
        {
          "name": "Function declaration parameter",
          "scope": ["variable.parameter.function"],
          "settings": {
            // I'm not sure whether this is the correct way or not. Anyway, this is working.
            "foreground": "#D6DEEB"
          }
        },
        {
          "name": "Function Argument",
          "scope": ["meta.function-call"],
          "settings": {
            "foreground": "#D6DEEB"
          }
        },
        {
          "name": "Object Property",
          "scope": ["variable.other.object.property"],
          "settings": {
            "foreground": "#7FDBCA"
          }
        },
        {
          "name": "Support Function",
          "scope": ["support.function"],
          "settings": {
            "foreground": "#82AAFF",
            "fontStyle": "italic"
          }
        },
        {
          "name": "Entity Type",
          "scope": [
            "entity.name.type",
            "entity.name.type.js",
            "entity.name.type.jsx",
            "entity.name.type.ts",
            "entity.name.type.tsx",
            "entity.name.type.module",
            "entity.name.type.module.js",
            "entity.name.type.module.jsx",
            "entity.name.type.module.ts",
            "entity.name.type.module.tsx",
            "support.class",
            "support.type",
            "storage.type.generic.java",
            "meta.definition.variable.java storage.type.java",
            "meta.method.identifier.java storage.type.java"
          ],
          "settings": {
            "foreground": "#ADDB67"
          }
        },
        {
          "name": "Entity Class (Including JS/TS Interface)",
          "scope": [
            "meta.class entity.name.type.class",
            "meta.class entity.name.type.class.js",
            "meta.class entity.name.type.class.jsx",
            "meta.class entity.name.type.class.ts",
            "meta.class entity.name.type.class.tsx",
            "entity.other.inherited-class",
            "meta.interface entity.name.type.interface.js",
            "meta.interface entity.name.type.interface.jsx",
            "meta.interface entity.name.type.interface.ts",
            "meta.interface entity.name.type.interface.tsx"
          ],
          "settings": {
            "foreground": "#ADDB67"
          }
        },
        {
          "name": "Entity Interface",
          "scope": ["meta.interface entity.name.type.interface"],
          "settings": {
            "foreground": "#35C37F"
          }
        },
        {
          "name": "Entity Enum",
          "scope": ["entity.name.type.enum"],
          "settings": {
            "foreground": "#ADDB67"
          }
        },
        {
          "name": "String Template",
          "scope": [
            "meta.template.expression.js",
            "meta.template.expression.jsx",
            "meta.template.expression.ts",
            "meta.template.expression.tsx"
          ],
          "settings": {
            "foreground": "#F36D75"
          }
        },
        {
          "name": "HTML/XML Entity Tag Name",
          "scope": ["entity.name.tag"],
          "settings": {
            "foreground": "#C5E478"
          }
        },
        {
          "name": "HTML/XML Entity Attribute Name",
          "scope": ["entity.other.attribute-name"],
          "settings": {
            "foreground": "#82AAFF"
          }
        },
        {
          "name": "JavaScript/TypeScript Object Key",
          "scope": ["meta.object.member"],
          "settings": {
            "foreground": "#7FDBCA"
          }
        },
        {
          "name": "React Tag Non-Component Name",
          "scope": ["entity.name.tag.jsx", "entity.name.tag.tsx"],
          "settings": {
            "foreground": "#35C37F"
          }
        },
        {
          "name": "React Tag Component Name",
          "scope": ["support.class.component.jsx", "support.class.component.tsx"],
          "settings": {
            "foreground": "#C9E290"
          }
        },
        {
          "name": "React Tag Attribute Name",
          "scope": ["entity.other.attribute-name.jsx", "entity.other.attribute-name.tsx"],
          "settings": {
            "foreground": "#53BDEC"
          }
        },
        {
          "name": "Java/Kotlin Annotation",
          "scope": [
            "meta.declaration.annotation.java",
            "meta.declaration.annotation.java storage.type.annotation.java",
            "entity.name.type.annotation.kotlin",
            "entity.name.type.annotation-site.kotlin"
          ],
          "settings": {
            "foreground": "#AB51BA"
          }
        },
        {
          "name": "Java Package/Import Statement Target",
          "scope": [
            "meta.package.java storage.modifier.package.java",
            "meta.import.java storage.modifier.import.java"
          ],
          "settings": {
            "foreground": "#D6DEEB"
          }
        },
        {
          "name": "Java Primitive Type",
          "scope": ["storage.type.primitive.java"],
          "settings": {
            "foreground": "#C792EA"
          }
        },
        {
          "name": "Python language constants",
          "scope": ["constant.language.python"],
          "settings": {
            "foreground": "#C792EA"
          }
        },
        {
          "name": "Python member attribute",
          "scope": ["source.python meta.member.access.python meta.attribute.python"],
          "settings": {
            "foreground": "#7FDBCA"
          }
        },
        {
          "name": "Python function call function name",
          "scope": ["meta.function-call.generic.python"],
          "settings": {
            "foreground": "#82AAFF"
          }
        },
        {
          "name": "Python function call argument parameter value",
          "scope": ["meta.function-call.arguments.python"],
          "settings": {
            // I'm not sure whether this is the correct way or not. Anyway, this is working.
            "foreground": "#D6DEEB"
          }
        },
        {
          "name": "Python function call argument parameter name",
          "scope": [
            "source.python meta.function-call.python meta.function-call.arguments.python variable.parameter.function-call.python"
          ],
          "settings": {
            "foreground": "#20999D"
          }
        },
        {
          "name": "JSON Property Key",
          "scope": ["support.type.property-name.json"],
          "settings": {
            "foreground": "#C5E478"
          }
        },
        {
          "name": "JSON Property Value",
          "scope": ["meta.structure.dictionary.value.json string.quoted.double"],
          "settings": {
            "foreground": "#ECC48D"
          }
        },
        {
          "name": "JSON Property Special Value",
          "scope": [
            "meta.structure.dictionary.json meta.structure.dictionary.value constant.language"
          ],
          "settings": {
            "foreground": "#C792EA"
          }
        },
        {
          "name": "Properties Property Key",
          "scope": ["keyword.other.definition.ini"],
          "settings": {
            "foreground": "#C5E478"
          }
        },
        {
          "name": "Properties Property Key-Value Separator",
          "scope": ["punctuation.separator.key-value.ini"],
          "settings": {
            "foreground": "#89DDF7"
          }
        },
        {
          "name": "YAML Entity Name Tag",
          "scope": ["entity.name.tag.yaml"],
          "settings": {
            "foreground": "#C5E478"
          }
        },
        {
          "name": "Markdown bold",
          "scope": ["markup.bold"],
          "settings": {
            "foreground": "#ADDB67",
            "fontStyle": "bold"
          }
        },
        {
          "name": "Markdown italic",
          "scope": ["markup.italic"],
          "settings": {
            "foreground": "#53BDEC",
            "fontStyle": "italic"
          }
        },
        {
          "name": "Markdown italic in heading",
          "scope": ["markup.heading.markdown markup.italic"],
          "settings": {
            "foreground": "#89DDF7",
            "fontStyle": "italic"
          }
        },
        {
          "name": "Markdown underline link",
          "scope": ["markup.underline.link"],
          "settings": {
            "foreground": "#C792EA",
            "fontStyle": "underline"
          }
        },
        {
          "name": "Makrdown character escape",
          "scope": ["constant.character.escape.markdown"],
          "settings": {
            "foreground": "#DF878F"
          }
        },
        {
          "name": "Markdown code - fenced code block",
          "scope": ["markup.fenced_code.block.markdown"],
          "settings": {
            "foreground": "#AFCFAF"
          }
        },
        {
          "name": "Markdown code - inline code",
          "scope": ["markup.inline.raw.string.markdown"],
          "settings": {
            "foreground": "#8FBC8F"
          }
        }
      ]
    }
  }
}

VS Code keybindings.json

macOS 기준!

[
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Claude Code Extension                                                    ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Use shift-enter for newline in `claude` CLI
  // (Generated w. `/terminal-setup` in `claude` CLI)
  {
    "key": "shift+enter",
    "command": "workbench.action.terminal.sendSequence",
    "args": { "text": "\u001b\r" },
    "when": "terminalFocus"
  },
  // Prevent intercepting alt-k by Claude Code extension
  {
    "key": "alt+k",
    "command": "-claude-vscode.insertAtMention",
    "when": "editorTextFocus"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Sidebars                                                                 ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Explorer sidebar
  {
    "key": "ctrl+alt+e",
    "command": "workbench.view.explorer"
  },
  // Search sidebar
  {
    "key": "ctrl+alt+f",
    "command": "workbench.action.findInFiles"
  },
  {
    "key": "shift+cmd+f",
    "command": "-workbench.action.findInFiles"
  },
  // Source Control sidebar
  {
    "key": "ctrl+alt+s",
    "command": "workbench.view.scm"
  },
  // Toggle sidebar
  {
    "key": "shift+cmd+0",
    "command": "workbench.action.toggleSidebarVisibility"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Build and run                                                            ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Build task
  {
    "key": "ctrl+b",
    "command": "workbench.action.tasks.build"
  },
  {
    "key": "cmd+b",
    "command": "-workbench.action.toggleSidebarVisibility"
  },
  // Run task
  {
    "key": "ctrl+x",
    "command": "workbench.action.tasks.test"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Editor tabs and groups                                                   ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Move focus between editor tabs (VIM arrow)
  {
    "key": "ctrl+h",
    "command": "workbench.action.previousEditor",
    "when": "!terminalFocus"
  },
  {
    "key": "ctrl+l",
    "command": "workbench.action.nextEditor",
    "when": "!terminalFocus"
  },
  // Move focus between editor groups (VIM arrow)
  {
    "key": "ctrl+shift+h",
    "command": "workbench.action.focusLeftGroup",
    "when": "!terminalFocus"
  },
  {
    "key": "ctrl+shift+l",
    "command": "workbench.action.focusRightGroup",
    "when": "!terminalFocus"
  },
  // Move editor tabs (VIM arrow)
  {
    "key": "ctrl+cmd+h",
    "command": "workbench.action.moveEditorLeftInGroup"
  },
  {
    "key": "ctrl+cmd+l",
    "command": "workbench.action.moveEditorRightInGroup"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Navigation                                                               ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Go back/forward
  {
    "key": "ctrl+alt+h",
    "command": "workbench.action.navigateBack",
    "when": "editorFocus"
  },
  {
    "key": "ctrl+alt+l",
    "command": "workbench.action.navigateForward",
    "when": "editorFocus"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Editor text                                                              ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Auto indention
  {
    "key": "shift+cmd+f",
    "command": "editor.action.formatDocument",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "shift+cmd+f",
    "command": "-workbench.view.search",
    "when": "!searchViewletVisible"
  },
  // Expand/shrink selection
  {
    "key": "alt+k",
    "command": "editor.action.smartSelect.expand",
    "when": "editorTextFocus"
  },
  {
    "key": "alt+k",
    "command": "-editor.action.accessibilityHelpConfigureKeybindings",
    "when": "accessibilityHelpIsShown && accessibleViewHasUnassignedKeybindings"
  },
  {
    "key": "alt+j",
    "command": "editor.action.smartSelect.shrink",
    "when": "editorTextFocus"
  },
  // Move line up/down (VIM arrow)
  {
    "key": "shift+alt+k",
    "command": "editor.action.moveLinesUpAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "shift+alt+j",
    "command": "editor.action.moveLinesDownAction",
    "when": "editorTextFocus && !editorReadonly"
  },
  // Editor suggestion (select prev/next)
  {
    "key": "ctrl+j",
    "command": "selectNextSuggestion",
    "when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus"
  },
  {
    "key": "ctrl+j",
    "command": "-editor.action.joinLines",
    "when": "editorTextFocus && !editorReadonly"
  },
  {
    "key": "ctrl+k",
    "command": "selectPrevSuggestion",
    "when": "suggestWidgetMultipleSuggestions && suggestWidgetVisible && textInputFocus"
  },
  {
    "key": "ctrl+k",
    "command": "-deleteAllRight",
    "when": "textInputFocus && !editorReadonly"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Code                                                                     ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Rename
  {
    "key": "shift+cmd+r",
    "command": "editor.action.rename",
    "when": "editorHasRenameProvider && editorTextFocus && !editorReadonly"
  },
  // Go to next/previous problem (JenBrains style)
  {
    "key": "f2",
    "command": "editor.action.marker.nextInFiles",
    "when": "editorFocus"
  },
  {
    "key": "f2",
    "command": "-editor.action.rename",
    "when": "editorHasRenameProvider && editorTextFocus && !editorReadonly"
  },
  {
    "key": "shift+f2",
    "command": "editor.action.marker.prevInFiles",
    "when": "editorFocus"
  },
  // Go to references(usages)
  {
    "key": "cmd+u",
    "command": "editor.action.goToReferences",
    "when": "editorHasReferenceProvider && editorTextFocus && !inReferenceSearchEditor && !isInEmbeddedEditor"
  },
  {
    "key": "cmd+u",
    "command": "-cursorUndo",
    "when": "textInputFocus"
  },
  // Quick fix (JetBrains style)
  {
    "key": "alt+enter",
    "command": "editor.action.quickFix",
    "when": "editorHasCodeActionsProvider && editorTextFocus && !editorReadonly"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Terminal                                                                 ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Create integrated terminal
  {
    "key": "alt+shift+`",
    "command": "workbench.action.terminal.new"
  },
  // Kill integrated terminal
  {
    "key": "ctrl+shift+`",
    "command": "workbench.action.terminal.kill"
  },
  // Move between integrated terminal tabs (VIM arrow)
  {
    "key": "ctrl+h",
    "command": "workbench.action.terminal.focusPrevious",
    "when": "terminalFocus && terminalHasBeenCreated && !terminalEditorFocus || terminalFocus && terminalProcessSupported && !terminalEditorFocus"
  },
  {
    "key": "ctrl+l",
    "command": "workbench.action.terminal.focusNext",
    "when": "terminalFocus && terminalHasBeenCreated && !terminalEditorFocus || terminalFocus && terminalProcessSupported && !terminalEditorFocus"
  },
  // Move focus between integrated terminal groups (VIM arrow)
  {
    "key": "ctrl+shift+h",
    "command": "workbench.action.terminal.focusPreviousPane",
    "when": "terminalFocus && terminalHasBeenCreated && terminalSplitPaneActive || terminalFocus && terminalProcessSupported && terminalSplitPaneActive"
  },
  {
    "key": "ctrl+shift+l",
    "command": "workbench.action.terminal.focusNextPane",
    "when": "terminalFocus && terminalHasBeenCreated && terminalSplitPaneActive || terminalFocus && terminalProcessSupported && terminalSplitPaneActive"
  },
  // Integrated terminal creation for Python VEnv
  {
    "key": "cmd+ctrl+shift+`",
    "command": "python.createTerminal"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Extension - Go to Next/Previous Member (VIM arrow)                       ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  {
    "key": "ctrl+alt+j",
    "command": "gotoNextPreviousMember.nextMember",
    "when": "editorTextFocus"
  },
  {
    "key": "ctrl+alt+k",
    "command": "gotoNextPreviousMember.previousMember",
    "when": "editorTextFocus"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Others                                                                   ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  // Show definition
  {
    "key": "cmd+b",
    "command": "editor.action.revealDefinition",
    "when": "editorHasDefinitionProvider && editorTextFocus && !isInEmbeddedEditor"
  },
  // Show hover
  {
    "key": "f1",
    "command": "editor.action.showHover",
    "when": "editorTextFocus"
  },
  // Developers: Inspect Editor Tokens and Scopes
  {
    "key": "ctrl+shift+cmd+i",
    "command": "editor.action.inspectTMScopes"
  },
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Remove conflicting keybindings                                           ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
  {
    "key": "shift+cmd+g",
    "command": "-editor.action.announceCursorPosition"
  }
  // ╔══════════════════════════════════════════════════════════════════════════╗
  // ║ Automatically added?                                                     ║
  // ╚══════════════════════════════════════════════════════════════════════════╝
]

DBeaver Community

DBeaver 설치

JDK가 필요하다.

macOS

brew install --cask dbeaver-community

DBeaver Preferences

Dark theme 설정

User Interface > Apperance

"Enable theming" 체크 상자를 설정하고, "Theme"을 "Dark Theme"로 둔다.

글꼴 설정

User Interface > Apperance > Colors and Fonts

"DBeaver Fonts > Monospace Font"를 "D2Coding, 15"로 설정한다.

SQL format 설정

Editors > SQL Editor > Formatting

"Settings" 영역에 있는 설정들을 바꾼다.

  • "Insert spaces for tabs" 체크 상자를 설정한다.
  • "Keyword case"를 "Upper"로 지정한다. (원래는 "Default")

Text editor 추가 설정

Editors > Text Editors

  • "Show line numbers" 체크 상자를 설정한다.
  • "Show whitespace characters" 체크 상자를 설정한다. "Configure visibility"를 눌러서 뜨는 dialog는 다음처럼 설정한다.
    • Space: Leading, Trailing
    • Tab: Leading, Enclosed, Trailing
    • Line Feed: (None)
    • Transparency level: 80 -> 63

Heap status 설정

General

"Show heap status" 체크 상자를 설정한다.

DBeaver 단축키 설정

User Interface > Keys

Action Category Default My binding
Execute SQL Query SQL Editor control-enter command-enter
Content Format SQL Editor control-shift-F shift-command-F

DBeaver Plugins

Eclipse plugin을 설치한다.

Help > Install New Software...


Postman

Postman 설치

Node.JS 런타임이 필요하다 (Interceptor 때문).

macOS

brew install --cask postman

macOS Interceptor 설치

macOS는 Chrome 라이브러리 디렉터리 권한 때문에 설치가 잘 안 된다 (~/Library/Application Support/Google/Chrome/NativeMessagingHosts).

FILE_PERMISSIONS_REQUIRED 오류로 인해 막힐 경우, 아래 웹페이지에서 직접 다운로드받아서 수작업으로 넣어본다.
https://learning.postman.com/docs/sending-requests/capturing-request-data/interceptor/#installing-interceptor

Chrome에서는 확장을 따로 설치해주면 된다.

'개발 > 개발 잡다' 카테고리의 다른 글

개발 환경 설정 (2023 ~ 2024)  (2) 2023.03.29
개발 환경 설정 (2020~2022)  (2) 2020.01.05
개발 설정 (2018~2019)  (0) 2018.01.25

+ Recent posts