今までdotenv-mode.elをフォークし、幾つかの関数を追加したり修正したりして使用してきた1。いい加減自分で実装しても良さそうな気がしてきたので実装した。よく考えている事なんだけれど、便利な機能を持つツールがあって、それが沢山の機能を持っている時、大抵はその機能の全てを使う訳じゃない。使わない機能があっても、気にしなければ良い話なんだけれど、使わない機能がたくさんある弊害というのもあると思う。例えば使わない機能によって脆弱性が紛れ込んでいたり、依存パッケージが増えていたり、使わない機能によって仕様やコードが大きくなり、修正したい特定の機能のコードを特定したり修正したりする事が難しくなってしまうという事が該当する。どの機能を使うのか、使わないのかというのは、人やその時々によって異なるから、一概にどのようなものが良いかという事は言えないのだけれど、今必要としているものがあり、今必要としていないものがない状態が理想的な状態なのだろう。モジュール化やパッケージ化という事には一定の意味があるけれど、機能を取捨選択できないという点はあるように思う。それは取り込まなければ良いのではというのもあるけれど、取り込まないコードであれば存在させていない方が良い。これは便利という点とのトレードオフのような関係でもあるから、正解はないかもしれないけれど、何が言いたいかと言うと「オーバーキルは良くない」という事だ。そういう点で私にとってオーバーキルにならないコードを書いた。
;;; dotenv.el --- dotenv for Emacs. -*- lexical-binding: t -*-
;; Copyright (C) 2023 TakesxiSximada
;; Author: TakesxiSximada
;; Maintainer: TakesxiSximada
;; Version: 1.1
;; Package-Version: 20230927.0001
;; Package-Requires: ((emacs "29.1") (s))
;; Date: 2023-09-27
;; This file is part of dotenv.el.
;; dotenv.el is free software: you can redistribute it and/or
;; modify it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;; dotenv.el is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; Affero General Public License for more details.
;; You should have received a copy of the GNU Affero General Public
;; License along with this program. If not, see
;; <https://www.gnu.org/licenses/>.
;;; Code:
(require 's)
(defun dotenv-parse-line (target-line)
(if-let* ((trimed-line (string-trim target-line))
(not-empty (not (string-empty-p trimed-line)))
(not-comment (not (string-prefix-p "#" trimed-line)))
(split-index (s-index-of "=" trimed-line)))
(cons
(substring trimed-line nil split-index)
(replace-regexp-in-string
"[\"']$" ""
(replace-regexp-in-string
"^[\"']" ""
(string-trim (substring trimed-line (+ split-index 1) nil)))))))
(defun dotenv-parse-entries (str)
(seq-filter (lambda (x) x)
(mapcar #'dotenv-parse-line
(string-split str "\n"))))
;;;###autoload
(defun dotenv-apply-global (dotenv-file-path &optional apply?)
(interactive (list
(read-file-name ".env file: ")
(yes-or-no-p "Apply?")))
(if-let* ((str (with-current-buffer (find-file-noselect dotenv-file-path)
(buffer-substring-no-properties (point-min) (point-max))))
(entries (dotenv-parse-entries str)))
(mapcar (lambda (entry) (setenv (car entry)
(if apply? (cdr entry))))
entries)))
(defun dotenv-get-process-environment (dotenv-file-path)
(if-let* ((str (with-current-buffer (find-file-noselect dotenv-file-path)
(buffer-substring-no-properties (point-min) (point-max))))
(entries (dotenv-parse-entries str)))
(mapcar (lambda (entry) (format "%s=%s" (car entry) (cdr entry)))
entries)))
(provide 'dotenv)
;;; dotenv.el ends here