Emacs에서는 모든 것이 서비스처럼 보인다
3 hours ago
3
- Emacs는 운영체제 자체라기보다 커널 위의 애플리케이션과 유틸리티를 조율하며, 파일 시스템·네트워크·외부 프로그램을 활용해 다양한 서비스의 클라이언트가 됨
- 클라이언트에 필요한 UI·통신 계층·로컬 데이터 저장소를 미니버퍼, 버퍼, URL, TCP/UDP, JSON, SQLite 같은 내장 라이브러리로 구성할 수 있음
- 동적 언어인 Emacs Lisp(Elisp) 는 Elisp 함수와 셸 명령을 실행 중에 결합해, Emacs가 접근할 수 있는 기능을 유연하게 조율함
- 예제 wttr 명령은 위치를 입력받아 wttr.in에 HTTP 요청을 보내고, JSON에서 지역·기온·날씨를 추출해 미니버퍼에 표시한 뒤 kill ring에도 저장함
- 전체 wttr.el은 cloc 기준 67줄이며, 네트워크 요청과 JSON 처리를 Python 같은 명령줄 도구에 맡기면 셸 명령 자체를 서비스로 삼는 더 짧은 Elisp 클라이언트도 만들 수 있음
운영체제 위에서 서비스를 조율하는 Emacs
- Emacs를 운영체제라고 부르는 표현은 정확하지 않지만, 운영체제 커널 위에서 애플리케이션과 유틸리티를 조율하는 능력 때문에 이런 비교가 생김
- 파일 시스템과 네트워크 같은 운영체제 서비스에 내장 기능으로 접근하고 다른 프로그램도 실행할 수 있어, Emacs 안에서 클라이언트 동작을 즉석에서 구성하기 쉬움
- 여러 클라이언트 모드로 많은 컴퓨팅 작업을 처리할 수 있으므로 사용자가 “Emacs 안에서만 생활한다”는 발상도 성립함
요청과 응답으로 보는 클라이언트-서버 모델
- 클라이언트-서버 모델은 자원을 제공하는 서비스와 이를 요청하는 클라이언트가 작업을 나누는 상호작용 패턴임
- 클라이언트가 요청을 보냄
- 서버가 요청을 처리한 뒤 응답을 반환함
- 요청과 응답으로 이뤄진 트랜잭션은 네트워크를 통하거나 한 시스템 안에서 로컬로 수행될 수 있음
- 네트워크 기반 모델은 REST 스타일 소프트웨어 아키텍처에서 폭넓게 발전함
Emacs 클라이언트를 이루는 세 영역
- 일반적인 클라이언트는 다음 세 영역을 담당함
- UI: 필요에 따라 사용자 입력과 출력을 처리함
- 클라이언트 경계(Client Edge): 서비스와 통신하며, 네트워크 클라이언트에서는 네트워크 하위 시스템이 이 역할을 맡음
- 로컬 데이터베이스: 서버와 교환하거나 동기화할 데이터를 표현하며, 구체적인 관리 방식은 구현 요구사항에 따라 달라짐
-
사용자 인터페이스 구성
-
서비스 통신과 데이터 변환
- 서비스에 연결되는 클라이언트 경계에는 다음 기능을 활용할 수 있음
- 직렬화와 역직렬화에는 내장 파서를 이용함
-
로컬 데이터 관리
- 서버 데이터의 로컬 표현에는 Elisp 컬렉션을 활용할 수 있음
- 영속적인 로컬 저장소가 필요하면 SQLite를 사용할 수 있음
- 실제 클라이언트의 복잡도는 요구사항에 따라 달라지며, 무거운 처리를 담당할 기존 명령줄 유틸리티가 있다면 셸 호출로 접근하는 서비스로 재구성할 수 있음
Elisp로 기능을 결합하는 방식
- 앞의 라이브러리는 모두 Emacs Lisp(Elisp)에서 접근할 수 있음
- Elisp는 실행 중 높은 수준의 즉흥적 구성을 허용하는 동적 프로그래밍 언어임
- Elisp 함수부터 셸 명령까지 Emacs가 사용할 수 있는 동작을 결합해 복잡한 흐름을 조율할 수 있음
wttr.in 날씨 클라이언트 구현
- wttr.in은 콘솔 중심의 일기예보 웹 서비스이며 JSON 출력을 지원함
- Emacs용 wttr 명령은 다음 순서로 동작함
- 사용자에게 위치를 입력받음
- wttr.in 요청 URL을 생성함
- HTTP 요청을 전송함
- JSON 응답을 처리함
- 결과를 미니버퍼에 표시하고 kill ring에 저장함
- 처리 중 오류가 발생하면 미니버퍼에 오류 메시지를 표시함
-
요청 URL 만들기
- wttr--request-url은 https://wttr.in을 기본 URL로 사용함
- 입력한 위치의 공백을 +로 바꾸고 /<location>?0&format=j1 형태의 쿼리를 생성함
- 완성된 URL은 이후 JSON 가져오기 함수로 전달됨
-
HTTP 요청과 JSON 파싱
- fetch-json-as-hash-table은 url-retrieve-synchronously로 URL을 동기적으로 가져옴
- 데이터를 받지 못하면 Failed to fetch data from <URL> 오류를 발생시킴
- 응답 버퍼에서 HTTP 메타데이터 헤더 뒤로 이동한 다음, json-parse-buffer로 나머지 내용을 Elisp hash-table 로 변환함
- 처리가 끝나면 내려받은 네트워크 버퍼를 항상 제거해 메모리 누수를 방지함
-
날씨 메시지 조합
- wttr--report-message는 JSON 데이터에서 다음 값을 추출함
- 가장 가까운 지역의 이름
- 지역
- 국가
- 현재 섭씨 기온 temp_C
- 현재 화씨 기온 temp_F
- 날씨 설명 weatherDesc
- 비어 있지 않은 위치 요소를 쉼표로 연결하고 위치: 섭씨, 화씨 날씨 설명 형식의 결과를 만듦
- 전체 구현은 wttr.el 소스에서 확인할 수 있음
명령줄 도구도 서비스로 활용하기
- Emacs API는 높은 수준의 추상화를 제공하며, HTTP 요청과 JSON 처리를 직접 구현한 wttr.el도 cloc 측정 기준 67줄임
- 더 단순한 대안은 실제 네트워크 요청과 JSON 처리를 weather라는 Python 스크립트에 맡기는 방식임
- Elisp의 weather 명령이 사용자에게 위치를 입력받음
- 위치를 인자로 붙여 weather 셸 명령을 구성함
- shell-command-to-string으로 명령을 실행함
- 반환 결과를 kill ring에 저장하고 미니버퍼에 표시함
- 이 구성에서는 셸 명령이 요청을 받는 서비스가 되고 Elisp 함수가 클라이언트 역할을 맡음
- Elisp의 동적 특성 덕분에 Elisp 라이브러리와 명령줄 유틸리티를 필요에 따라 결합할 수 있으며, 이런 통합 가능성이 Emacs 안에서 모든 것을 서비스처럼 다룰 수 있게 함
-
Homepage
-
Tech blog
- Emacs에서는 모든 것이 서비스처럼 보인다