2 minute read

org-mode 문서에 링크를 추가할 일이 있으면 Org-cliplink 패키지를 사용한다. 로그인해야 접근할 수 있는 ConfluenceJira 페이지도 Org-cliplink를 사용할 수 있게 확장하는 작업을 했다. 특정 주소로 시작하면 API를 호출해서 페이지 정보를 가져오는 방식으로 처리했다.

같은 방식은 아니지만 GitLab issue와 merge request를 org-mode 문서에 링크로 추가할 수 있는 코드를 짰었다. Org-cliplink를 알기 전이라 함수를 호출하고 issue나 merge request 번호를 입력해야 한다. GitLab merge request 링크도 Org-cliplink로 인터페이스를 통일하는 작업을 했다.

URL을 파싱해서 정보를 가져오기

GitLab URL structure에 - 구획 문자(delimiter)를 사용한다. Slack 봇인 Slab을 만들 때, 구획 문자가 추가된 GitLab 버전을 반영하느라 투덜거렸던 기억이 난다. 그때는 group 정보를 따로 빼낼 필요가 없어서 몰랐다. group, subgroup, project 정보와 page 정보를 파싱하는데 - 구획 문자가 있으니 편하다.

(defun my/gitlab--extract-groups-and-mr-id (url end_point)
  (let* ((url-without-endpoint (replace-regexp-in-string (concat "^" end_point) "" url))
         (url_parts (split-string url-without-endpoint "/-/"))
         (mr-id (my/gitlab--merge-request-id (cadr url_parts))))
    (list :groups (my/gitlab-remove-leading-slash (car url_parts)) :mr-id mr-id)))

(defun my/gitlab--merge-request-id (url)
  (save-match-data
    (if (string-match "/?merge_requests/\\([0-9]+\\)" url)
        (string-to-number (match-string 1 url)))))

(defun my/gitlab-remove-leading-slash (url)
  (replace-regexp-in-string "^/" "" url))

(my/gitlab--extract-groups-and-mr-id "https://gitlab.com/abc/def/ghi/-/merge_requests/123" "https://gitlab.com")
(:groups "abc/def/ghi" :mr-id 123)

group 정보와 merge request id는 https://gitlab.com/api/v4/projects/abc%2Fdef%2Fghi/merge_requests/123 처럼 호출 API URL을 만들 때, 사용한다.

Org-cliplink와 연동할 my/gitlab-merge-request-title 함수

함수 인자로 URL을 받는다. 설정으로 추가한 host 정보와 일치하면 Auth-source에 저장한 private token을 사용해서 GitLab API를 호출한다. 만약 실패하면 nil 을 리턴한다.

(defun my/gitlab-merge-request-title (url)
  (when-let (content (my/gitlab-merge-request url))
    (concat (plist-get content :reference) " " (plist-get content :title))))

(defun my/gitlab-merge-request (url)
  (when-let* ((host (my/gitlab--find-host url my/gitlab-hosts))
              (request-url (my/gitlab--merge-request-url url host))
              (header (my/gitlab--auth (plist-get host :url)))
              (content (my/gitlab--get-merge-request request-url header)))
    content))

full reference를 사용해서 gitlab-org/gitlab!23066 Move merge request routes under /-/ scope 와 같이 title을 구성한다.

Org-cliplink를 확장하려고 추가한 hook 변수my/gitlab-merge-request-title 함수를 추가한다.

(setq my/org-cliplink-custom-retrieve-title-hook
      (lambda (url)
        (or (my/org-cliplink-confluence-title url)
            (my/jira-title url)
            (my/gitlab-merge-request-title url))))

Org-mode heading으로 삽입할 my/gitlab-insert-heading-content

Jira 이슈 정보를 Emacs Org-mode 문서에 삽입’ 글에서 짠 함수와 비슷하게 키를 바인딩할 함수를 짰다. 클립보드에 URL이 있으면 그걸 사용하고 없으면 URL 입력 프롬프트를 띄우게 했다.

(defun my/gitlab-insert-heading-content ()
  (interactive)
  (let* ((url (my/gitlab--url-clipboard-or-prompt))
         (content (my/gitlab-merge-request url))
         (reference (plist-get content :reference))
         (title (plist-get content :title)))
    (org-insert-heading)
    (insert (format "%s %s [/]" reference title))
    (org-update-statistics-cookies nil)
    (org-set-property "URL" url)))

(defun my/gitlab--url-clipboard-or-prompt ()
  (let ((clipboard-content (gui-get-selection 'CLIPBOARD)))
    (if (and clipboard-content (string-match-p "^http" clipboard-content))
        clipboard-content
      (read-string "Enter URL: "))))

Doom Emacs 함수를 사용해서 SPC m z g 키로 바인딩했다.

(map! :map org-mode-map
      :localleader
      (:prefix ("z" . "insert")
               "g" #'my/gitlab-insert-heading-content))

마치며

Org-cliplink와 SPC m z 키바인딩으로 org-mode 문서 링크 추가 인터페이스를 통일했다. 어떤 URL이던지 clipboard에 복사하고 SPC m l c 키를 누르면 링크가 추가되니 편하다. org-mode 문서 heading을 추가하는 건 SPC m z 키바인딩으로 통일해서 이제 손에도 익숙하다. 전체 코드는 ohyecloudy/dotfiles/commit/94028ad00ac 커밋으로 볼 수 있다.

C-x C-s C-x C-c

링크