-
나의 첫 오픈소스 PR 이야기Programming/Contribution 2024. 9. 30. 00:00
오픈소스에 처음으로 기여하게 된 이야기를 나눠보려 합니다. 블로그 코드 블럭을 예쁘게 꾸미고 싶어서 에디터 테마를 이것저것 구경하다가, 우연히 작은 버그를 발견하고 수정하게 된 이야기입니다.
Intro
4년간의 대학 전공 대신, 개발자의 길을 선택했습니다. 결정적 요인 중 하나는 개발자들의 문화였습니다. 특히 코드와 지식을 서로 공유하는 오픈소스 문화말이죠.
현대 사회 핵심 기술들의 소스 코드가 공개되어 있는 게 참 신기했고, 코드를 공유하고 서로 개선해 나가는 문화는 매력적이었습니다. 리누스 토발즈 선생님 같은 오픈소스 개발자를 동경하며, 언젠가 코딩 실력이 늘어나면 나도 오픈소스에 기여하고 싶다고 생각했습니다.
그 언젠가는 생각보다 금방 찾아왔습니다.
공부를 시작하고 얼마 되지 않아, 오픈 소스에 첫 PR(Pull Request)을 보냈습니다.
그것도 제가 매일 사용하는 코드 에디터의 UI 플러그인에 말이죠.해결한 문제는 정말 사소했습니다.
에디터 테마 변경 시 이전 테마의 색상이 일부 남아있는 문제였습니다.숫자의 색상 변화를 면밀히 관찰해보면, 선택한 테마와 무관하게 값이 계속 보라색으로 칠해져있습니다.
함수나 변수 이름에는 이런 문제가 없었습니다. 숫자 리터럴 값만 이런 색칠 이슈가 발생했습니다.
UI 플러그인 코드에서 숫자 설정을 제대로 지정하지 않아서 생긴 문제였습니다. 작성할 때 빼먹은거죠.테마를 전환할 때 생기는 문제이기 대문에, 프로그램을 재시작하면 자연스럽게 문제가 해결됩니다.
코드 편집기의 테마 변경은 자주 하는 작업이 아니죠. 그래서 지금껏 이 문제를 아무도 발견하지 못했나 봅니다.
매일 아침 테마를 둘러보며 "오늘의 기분에 맞춘 테마"를 고르는 개발자는 (아마) 거의 없을 테니까요.제가 남긴 PR은 이 빼먹은 설정값을 추가한 단 1줄짜리 코드였습니다.
짧은 수정이었지만, 이런 사소한 방식으로도 오픈 소스에 기여할 수 있구나 라는 깨달음을 얻을 수 있었습니다.
복잡한 로직이나 기술을 이용해 새로운 기능을 추가하거나, 프로젝트나 도메인에 대한 엄청난 지식을 바탕으로 버그를 찾거나 해결하는 것만 기여하는 방법이라고 생각했었거든요.처음부터 오픈소스 기여를 목적으로 코드를 읽고 분석한 것은 아니었습니다.
코드의 문제를 발견하고 해결한건, 마침 제가 티스토리 블로그를 꾸미는 데에 관심이 있었기 때문이었습니다.
블로그 코드에 적용할 색상을 참고하기 위해 여러 테마를 둘러보고, 색상 코드(#ACACAC
)를 보기 위해 UI 플러그인 코드를 열어보게 되었거든요.이 글에서는 블로그 꾸미기부터 시작해, 생애 첫 PR을 보내기 까지의 과정을 시간순으로 설명해볼까합니다.
마치 일기처럼 사고의 흐름을 따라가며 이야기하려 해요. 내용 특성상 낯선 개념이 많을 수 있습니다만, 어려운 내용은 없으니 찬찬히 읽어 주세요.이 별 거 아닌 경험이 오픈소스에 첫 발을 내딛고 싶지만 부담스러워하는 분들의 부담을 더는 데 작은 도움이 되면 좋겠습니다.
티스토리 블로그 코드 블럭 꾸미기
학교 졸업 후 본격적으로 프로그래밍 공부에 나섰습니다. CS:APP(컴퓨터 시스템) 책을 보며 과제를 풀고 있었는데요.
그 중 하나가 Bomb Lab 이라는 리버스 엔지니어링 과제였습니다.objdump
프로그램을 사용해 어셈블리 코드를 분석하는 과제죠.과제를 풀고 난 후, 풀이 과정을 정리해 블로그에 올렸습니다.
블로그 화면에서 확인한 제 글은... 읽기 너무 힘들었습니다.
긴 어셈블리 코드를 구문 강조도 없이 보여주니 가독성이 좋지 않았습니다.
글쓰기에는 자신이 없으니, 최소한 코드라도 보기 좋아야 누군가라도 글을 읽어주지 않을까 생각했습니다.이런 코드는 읽기 힘들지만.
0000000000400da0 <main>: 400da0: 53 push %rbx 400da1: 83 ff 01 cmp $0x1,%edi 400da4: /-- 75 10 jne 400db6 <main+0x16> 400da6: | 48 8b 05 9b 29 20 00 mov 0x20299b(%rip),%rax # 603748 <stdin@GLIBC_2.2.5> 400dad: | 48 89 05 b4 29 20 00 mov %rax,0x2029b4(%rip) # 603768 <infile> 400db4: /--|-- eb 63 jmp 400e19 <main+0x79> 400db6: | \-> 48 89 f3 mov %rsi,%rbx 400db9: | 83 ff 02 cmp $0x2,%edi
이러면 좀 낫죠.
0000000000400da0 <main>: 400da0: 53 push %rbx 400da1: 83 ff 01 cmp $0x1,%edi 400da4: /-- 75 10 jne 400db6 <main+0x16> 400da6: | 48 8b 05 9b 29 20 00 mov 0x20299b(%rip),%rax # 603748 <stdin@GLIBC_2.2.5> 400dad: | 48 89 05 b4 29 20 00 mov %rax,0x2029b4(%rip) # 603768 <infile> 400db4: /--|-- eb 63 jmp 400e19 <main+0x79> 400db6: | \-> 48 89 f3 mov %rsi,%rbx 400db9: | 83 ff 02 cmp $0x2,%edi
그래서 티스토리 기본 코드블럭 대신 prism.js를 사용하기로 했습니다.
웹페이지에서 프로그래밍 언어 요소(토큰)을 인식하고, css 클래스를 적용해, 적절한 색상을 입혀주는 라이브러리입니다.prism.js
는 티스토리 기본 코드블럭보다 지원하는 프로그래밍 언어가 훨씬 많습니다.
물론 위에 있는objdump
출력 형식을 인식하고 색칠해주지는 않습니다.
대신 직접 커스텀 언어를 만들어서 추가하는 건 가능하죠.
그래서 이를 위한 구문 분석 규칙을 자바스크립트로 직접 작성해서 넣어주었습니다.테마도 티스토리 기본 코드블럭 보다 더 다양하고, 예쁜 테마가 많습니다. 커스텀 테마 제작 역시 가능합니다.
이번에도 저는 커스텀 테마를 직접 만들어 적용하기로 했습니다.
이유는 간단합니다. 코드 편집 화면이랑 블로그 코드랑 똑같은 색상을 적용하고 싶었기 때문이죠.prism.js
에서 코드 색상은 css 파일을 통해 적용됩니다.
자바스크립트 코드가 구분한 문법 토큰에 html 클래스를 붙여주면, css 파일에서 색상을 입혀주는 방식입니다.
아래처럼 숫자는 자두색 문자열은 녹색 이렇게요..token.number { color: #905; } .token.string, .token.char { color: #690; }
제 코드 에디터 속 숫자가
#fe8019
주황색이라면, 제 커스텀 테마 파일은 이렇게 작성하면 되겠죠..token.number { color: #fe8019; }
근데 코드 에디터에서 언어 문법 토큰 별로 어떤 색깔을 쓰는지 어떻게 확인할까요?
내 코드엔 무슨 색깔이 들어갈까?
담당자가 누구죠?
궁금한 게 있으면 담당자를 찾아서 물어봐야겠죠. 코드 에디터에서 누가 코드를 칠하고 있는지 찾아봐야 합니다.
제가 사용하는 에디터는 Neovim입니다. 리눅스에 기본으로 깔려있는 vim 현대판 느낌의 에디터입니다.
가볍고 확장성이 높은 장점이 있지만, 그만큼 설정이 힘들고 복잡하다는 단점도 있습니다.
Vscode같은 IDE처럼 사용하려면 필요한 설정 파일과 플러그인이 엄청 많습니다.
레딧 Neovim 커뮤니티 설문을 보면, 설정 파일이 500줄이 넘어가는 유저가 절반 이상일 정도죠.그래서 저는 NvChad라는 Neovim 디스트로를 사용하고 있습니다.
복잡한 설정과 기본적인 플러그인을 미리 세팅해 주는 버전입니다.
덕분에 저같은 초보자도 비교적 쉽게 Neovim에 입문하고 적응할 수 있죠.종합하면, Neovim내 모든 설정은 제가 별도로 세팅하지 않았다면 NvChad에서 알아서 설정해준 것입니다.
그러니 코드를 색칠하는 것 역시 NvChad에서 설정했음이 분명합니다. 코드 colorscheme 테마 이름도 gruvchad입니다.
이름부터 누가 만들었는지 알 수 있습니다.테마를 변경하면 칠해진 코드의 색상도 달리집니다.
테마의 설정 파일을 한 번 찾아보면, 거기서 필요한 색상 코드를 얻을 수 있겠죠.gruvchad로 파일 검색을 수행하여 어렵지 않게
gruvchad.lua
파일을 찾아낼 수 있었습니다.파일은 NvChad에서 코드 하이라이팅을 담당하는 base46 플러그인 내부에 있었습니다.
Base46
이 바로 담당자였습니다.Base46 플러그인
플러그인 내부
gruvchad.lua
파일 내용입니다.local M = {} M.base_30 = { white = "#ebdbb2", darker_black = "#232323", black = "#282828", -- nvim bg black2 = "#2e2e2e", one_bg = "#353535", -- ... } M.base_16 = { base00 = "#282828", base01 = "#3c3836", base02 = "#423e3c", base03 = "#484442", base04 = "#bdae93", base05 = "#d5c4a1", base06 = "#ebdbb2", base07 = "#fbf1c7", base08 = "#fb4934", base09 = "#fe8019", base0A = "#fabd2f", base0B = "#b8bb26", base0C = "#8ec07c", base0D = "#83a598", base0E = "#d3869b", base0F = "#d65d0e", }
원하던 컬러 코드를 잔뜩 찾았습니다. 다만 한가지 문제가 있습니다.
각 색상이 어떤 토큰에 적용되는 지 나와있지 않다는 점입니다.
숫자는 무슨 색으로 칠하고, 함수는 어떤 색으로 칠하는 지 알아야 하는 데 말이죠.검색을 통해 Base 16 Styling Guide에 대해 알게되었습니다.
Base64
와 같은 인코딩 방식인줄 알았는데, 아예 다른 개념이었습니다.Base 16
은 코드 하이라이팅을 위한 색상 팔레트를 정의하는 방식이었습니다.base00
은 배경색,base01
은 주석,base08
은 변수명,base0D
는 함수명.
이렇게 색상과 사용법을 연결하는 하나의 인터페이스 프로토콜 인거죠.컬러 테마 제작자가 위의
gruvchad.lua
파일처럼 이 사용법에 맞게 16개의 색상값을 정의해놓으면, 코드 하이라이팅 구현 프로그램은 토큰에 대응되는base16
컬러 코드를 테마에서 찾아 적용하는 방식입니다.NvChad의 테마 플러그인 이름이
base46
인 이유는base16
테마를 기반으로 하되, UI 요소를 위한 색상을 30개 추가로 정의해서 쓰기 때문이었고요.그러면 어디엔가 언어 토큰과
base16
색상을 연결하는 코드도 있을텐데요.
플러그인 내syntax.lua
파일에서 관련 내용을 찾아볼 수 있었습니다.local syntax = { Boolean = { fg = theme.base09 }, Character = { fg = theme.base08 }, Conditional = { fg = theme.base0E }, Constant = { fg = theme.base08 }, -- ... }
Boolean
을base09
로 정의하고 있습니다.
gruvchad 테마에서base09
는 주황색이었죠. 코드 내Boolean
토큰은 이런 방식으로 주황색으로 칠해지게 된 것입니다.그런데 막상 비교해보니, 제 편집 환경과
syntax.lua
파일에서 정의한 색상이 완벽히 일치하지 않았습니다.vim 내에서
:Inspect
명령어를 쓰면, 현재 커서가 위치한 토큰의 색상 그룹을 확인할 수 있다고 합니다.
C언어의NULL
키워드에 커서를 두고:Inspect
를 실행해 보았습니다. 아래와 같은 결과가 나왔습니다.Treesitter - @constant.builtin.c links to @constant.builtin c
Treesitter라는 플러그인이 에디터의 코드 구문 분석을 담당하고 있었습니다.
기본 구문 분석보다 훨씬 세부적인 분석을 언어별로 제공하는 플러그인인데요.
코드 하이라이팅 역시treesitter
가 파싱한 토큰을 기반으로 색상이 입혀지고 있었습니다.base46
플러그인에treesitter.lua
파일 역시 존재하고 있었습니다.
같은 변수명이라도 언어의 빌트인 변수인지, 멤버 변수인지, 함수 인자인지에 따라 다른 색상을 적용할 수 있는 모습입니다.return { ["@variable"] = { fg = theme.base05 }, ["@variable.builtin"] = { fg = theme.base09 }, ["@variable.parameter"] = { fg = theme.base08 }, ["@variable.member"] = { fg = theme.base08 }, ["@variable.member.key"] = { fg = theme.base08 }, ["@module"] = { fg = theme.base08 }, -- ["@module.builtin"] = { fg = theme.base08 }, ["@constant"] = { fg = theme.base08 }, ["@constant.builtin"] = { fg = theme.base09 }, -- ... }
이렇게 해서
prism.js
에 들어갈 커스텀 css파일을 작성할 수 있게 되었습니다.함수 색칠을 예시로 들어보면,
treesitter.lua
파일이나syntax.lua
파일에서 함수 토큰에 해당되는base16
색상을 찾고,gruvchad.lua
파일에서 해당base16
에 어떤 컬러코드가 적혀있는지만 확인해 본 후,prism.js
에 들어갈 css 파일의token.function
색상을 수정하면 되는거죠.이슈 발견
이쯤 문득 그런 생각이 들었습니다. 지금까지 사용해온 gruvchad 테마, 정말 내 취향일까?
처음 Neovim 테마를 고를 때는 별 생각 없이 테마를 선택했거든요.
prism.js
의 css파일 작성에 나름 공수가 들어가니까, 작성하기 전 이참에 다른 테마도 한번 살펴보자는 생각이 들었습니다.그렇게 테마들을 둘러보면서 서문에서 언급한 문제를 발견하게 되었습니다.
에디터 테마를 변경할 때 이전 테마의 색상이 일부 남아있는 문제였죠.앞서 서술한 과정을 통해, 마침 저는 아래 두 가지 지식을 알고 있었습니다.
:Inspect
명령어로 현재 토큰을 색칠하는 데 사용된 색상 그룹을 확인하는 법base46
플러그인의 파일 구조와 색상 정의 방식
이 둘을 조합하여 오류가 생긴 이유를 어렵지 않게 파악할 수 있었습니다.
왜 이런 문제가 생겼는가
숫자 설정을 제대로 지정하지 않아서 발생한 문제입니다.
정확히는treesitter.lua
파일에서[@number]
토큰에 대한 색상 정의가 누락된 것이 원인이었습니다.여기서 잠깐,
base46
플러그인이 코드를 색칠하는 방법 기억 하시나요?syntax.lua
나treesitter.lua
파일에서 토큰과base16
색상을 매핑하는 규칙을 정의하면,
컬러 테마 파일은 여기에 쓰일 16개의 색상코드만 정의하는 방식이었죠.테마의 추구미에 따라, 미리 정의한 규칙을 따르고 싶지 않을 수도 있습니다.
함수와 메서드를 같은 색으로 칠하는 게 마음에 들지 않는다던가 하는 이유로요.그런 경우를 위해
base46
플러그인에서는 테마가 특정 토큰에 대한 규칙을 재정의하는 것 또한 지원합니다.
아래 chadracula 테마는 빌트인 함수를 청록색으로, 숫자를 보라색으로 칠하고 싶나 봅니다.-- chadracula -- M.polish_hl = { treesiter = { ["@function.builtin"] = { fg = M.base_30.cyan }, ["@number"] = { fg = M.base_30.purple }, }, }
chadracula 테마가
[@number]
토큰을 보라색으로 정의했습니다.
이후 테마를 바꾸어도[@number]
토큰은 보라색으로 칠해질 것입니다.
다른 테마는 기본 설정에 있는 토큰과 생상의 정의를 사용하는데, 여기에[@number]
토큰에 대한 정의가 없으니까요.
이전에 보라색으로 칠해진 숫자가 남아있는 것이었습니다.해결은 간단했습니다.
treesitter.lua
파일에 들어가 다음 한 줄을 추가하면 끝입니다.["@number"] = { fg = theme.base09 },
해결한 이슈를 어떻게 알려야 할까?
그렇게 문제를 해결하고 나서 한 가지 고민이 생겼습니다.
문제와 해결 방법을 어떻게 알려야 하는가 하는 고민이었습니다.깃허브에 Issue를 남겨야 하는지, PR을 보내야하는지, 개발자가
[@number]
를 포함하지 않은 데에 내가 모르는 중요한 이유가 있을 법도 한데, 어떻게 이야기를 꺼내야 할지 도무지 모르겠더라고요.그래서 마침 NvChad 디스코드 채널이 있길래, 들어가서 이 문제를 물어보기로 했습니다.
이런 이슈를 발견했고, 이유는
[@number]
가 누락된 것이라고 생각되는데, 혹시 이게 빠져있는 데에 어떠한 이유가 있는지, 오류 화면 영상 캡쳐와 함께 물어봤습니다.메인테이너는 그냥 빠뜨린 것 같다며 PR을 보내달라고 답했습니다.
아하! 그냥 빠트린거였구만.
괜히 제가 모르는 의도가 있을 것 같아서 필요 이상의 걱정을 좀 했던 것 같습니다.
근데 PR이요...?
PR이 무엇인지는 어렴풋이 알고 있었지만, 어떻게 해야 하는지는 잘 알지 못했습니다.
그도 그럴 게 저는 Git 사용법도 잘 몰랐었으니까요.PR 보내는 방법을 열심히 찾아보기 시작했습니다.
레포지토리를 포크하고, 코드를 수정하고... 인터넷 가이드를 열심히 따라했습니다.
수정할 내용이 한 줄 밖에 안되니, 코드는 Github 웹사이트에서 직접 수정했습니다.그러다 커밋 메시지를 잘못 썼는데, 되돌리는 방법을 잘 몰라서 포크한 저장소를 삭제하고 다시 만들기도 했습니다.
그렇게 우여곡절 끝에 떠듬떠듬 첫 PR을 보냈습니다.
디스코드에서 미리 얘기했어서 그런지, PR을 보내자마자 금방 메인테이너가 확인하고 머지해주었습니다.
Outro
별거 아니지만 오픈소스 첫 기여라는 점에서 엄청 뿌듯한 경험이었습니다.
특히 처음에 언급했듯 초심자도 기여할 방법과 방향성이 있다는 것을 알게 된 게 가장 큰 수확이었습니다.이후로도 NvChad의 코드 실행 터미널의 오류를 고치거나, direnv 같은 오픈소스 툴 문서에 기능이 추가된 버전을 명시하는 등,
사용하는 프로그램에서 사소한 문제를 발견하면 한번씩 들여다보고 고민해보면서 기여하려고 노력하고 있습니다.언젠가는 더 복잡하고 중대한 문제 해결에도 도전해보고 싶지만, 이렇게 작은 기여부터 시작해나가는 것도 하나의 의미있는 참여 방법이라고 생각합니다.
오픈소스에 기여하고 싶지만 어떻게 시작해야 할지 모르는 분들에게 제 경험이 작은 용기가 되었으면 좋겠습니다.
감사합니다!