これまで、バッチファイルを利用して環境変数の値を変更しながら Emacs 25 を起動するようにした。そして emacsclinet を利用しているかのような挙動を実現することも試みてきた。
その後、これまで利用してきた gnupack の startup_config.ini を参考にし、その stratup_config.ini と同一の方法での環境変数を設定する AutoHotkey 用スクリプトを作成した。[Local Variable]に emacs のパスを記載し、[Process Variable] に上書きしたい環境変数の値を記入する。これを使えば、以前利用したバッチファイルを用いる必要はない。
なお、このスクリプトを流用すれば、 gnupack の startup_cygwin.exe, startup_gvim.exe などの機能も容易に実装できるだろう。
;; -*-mode: ahk; coding:utf-8-with-signature-dos ; tab-width : 4 -*-" /* -----emacsを起動するためのスクリプト--- emacsclientw.exe とサーバー機能を使っているかのように runemacs.exe を使う (emacsclientwとserverファイルのどちらも使用しない) emacsが起動してないときには起動、起動してる時はアクティブ化、ファイルを送ると読み込む。 msys2版emacsで使うことを想定している AutoHotKey_Lw / Ahk2Exe_Lで動作 [1] コンパイルして適当な場所に置く emacsと同一のフォルダ内に置く必要は無い [2] iniファイルを作成する このプログラムと同じ場所に startup_config.iniを作成する そして、セクション名は "Local Variable" とし emacs.exe キーに renemacs.exe のパスを記述する [Local Variable] emacs.exe = <runemacs.exeのパス> この<runemacs.exeのパス>は変数を利用した表記方法も可能だ。 たとえば emacs.exe をこのように設定すると [Local Variable] msys64_directory = C:\msys64 emacs.exe = %msys64_directory%\usr\local\bin\runemacs.exe 実際に展開されるのは emacs.exe = C:\msys64\usr\local\bin\runemacs.exe である また、HOME や PATH のような環境変数を上書きしたうえで Emacsを起動することもできる。 "Process Variable" セクションに書く。 [Process Variable] msys64_directory = C:\msys64 HOME = %msys64_directory%\home\%USERNAME% PATH = %msys64_directory%\usr\bin;%PATH%; PATH = %msys64_directory%\usr\local\bin;%PATH%; PATH = %msys64_directory%\opt\bin;%PATH%; PATH = %msys64_directory%\mingw64\bin;%PATH%; PATH = %msys64_directory%\usr\bin\site_perl;%PATH%; PATH = %msys64_directory%\usr\bin\vendor_perl;%PATH%; PATH = %msys64_directory%\usr\bin\core_perl;%PATH%; [3] 起動する ファイルを送れば開く(複数ファイルの編集可)。 ショートカット作成や関連付けに使う。 以下のページを参考にしました。 [Windows]gnupackのemacsclientw.exeを快適に使えるようにする。 - Qiita http://qiita.com/acple@github/items/4be7eb774a28d574281e ---------------------------------------------------------------- */ #NoEnv SendMode Input SetWorkingDir %A_ScriptDir% #SingleInstance force DetectHiddenWindows,On ;; iniファイル名を指定 ini_file := "startup_config.ini" ; emacs のパス ini_local_section := "Local Variable" ; 一時的に環境変数を設定するセクション名 ini_process_section := "Process Variable" ;; ============================================================= ;; iniファイルをもとに、一時的に環境変数を設定する updateEnv(storeVariables(readIniVariables(ini_file, ini_process_section))) obj := storeVariables(readIniVariables(ini_file, ini_local_section)) ;; emacsを起動する(既に起動していない場合) ; 既に起動しているならば、フォアグラウンドに移す ret := startEmacs(find_item(obj, "emacs.exe")) ; 起動後すぐに drag and drop をすると ; ファイルの編集に失敗することがあったので ; 一定時間をあけておく if (TRUE == ret ) { sleep, 500 } ;; 引数からファイルの情報を取得する files := GetArgs() ;; ファイルを個別にドラッグ・アンド・ドロップ drag_and_drop_files_to_emacs(files) ExitApp ; ======================================== ; join(obj) ; { ; s:= "" ; For k, v in obj ; s .= k "=" v "`n" ; return s ; } find_item(obj, key) { if ({} == obj) { return "" } ret := get_next_index(obj, key) if (FALSE == ret) { return "" } return obj[ret] } get_next_index(obj, key) { for i, v in obj { if (key == v) { return i + 1 } } return False } storeVariables(lines) { obj := {} Loop, Parse, lines, `n, `r { Try { ; "<left hand side (lhs)> = <right hand side (rhs)>" ret := RegExMatch(Trim(A_LoopField), "^(.+?)=(.*)$", $) ; 行頭に = があるときか ; 行中に = がないとき if (0 == ret) { Throw "不正な設定です`n" . "設定値:" . Trim(A_LoopField) } lhs := Trim($1) rhs := expand_variables(Trim($2), obj) ; キーと値がまだ設定されていなければ ; 登録 next_index := get_next_index(obj, lhs) if (FALSE == next_index) { obj.push(lhs) obj.push(rhs) continue } obj[next_index] := rhs } Catch e { MsgBox, % "環境変数の一時的な設定のエラー`n" . e . "`n" . "プログラムを続行します" } } return obj } expand_variables(string, obj) { result := "" Loop, Parse, string, `% { ; A_Index が偶数の場合に、その文字列をもとに環境変数を取得 ; 奇数の場合には処理中断 if (1==Mod(A_Index, 2)) { result .= A_LoopField continue } ; 変数の値を明示的に設定していない場合 next_index := get_next_index(obj, A_LoopField) if (FALSE == next_index) { ; 環境変数の値を利用する result .= getEnv(A_LoopField) continue } result .= find_item(obj, A_LoopField) } return result } readIniVariables(ini_file, ini_section) { Try { If not (FileExist(ini_file)) { Throw "ini_file のパスが見つかりません`n" . "設定値:" . ini_file } IniRead, Variables, %ini_file%, %ini_section% } Catch e { MsgBox,% "ファイル指定のエラー`n" . e . "`n" . "プログラムを終了します" ExitApp } return Variables } updateEnv(obj) { for i, v in obj { ; A_Index が偶数の場合に、その文字列をもとに環境変数を取得 ; 偶数の場合には処理中断 if (0==Mod(A_Index, 2)) { continue } key := obj[i] value := obj[i + 1] EnvSet, %key%, %value% } } getEnv(string) { EnvGet, OutputVar, %string% return OutputVar } GetArgs() { global _ArgCount=%0% _Args := {} Loop, %_ArgCount% { _Args.push(%A_Index%) } return _Args } ; ======================================== startEmacs(path) { hwnd := WinExist("ahk_class Emacs") ; Emacs が既に起動している場合 if (hwnd) { ; emacs のアクティブ化 WinActivate, ahk_id %hwnd% return False } Try { if not (FileExist(path)) { Throw "不正確なパスです`n" . "設定値:" . path } Run, % path return True } Catch e { MsgBox, % "実行プログラムが見つかりません`n" . e . "`n" . "プログラムを終了します" ExitApp } } drag_and_drop_files_to_emacs(files) { Try { Loop, % files.length() { the_file := files[A_Index] ; 複数ファイルの存在を確認する if not (FileExist(the_file)) { Throw "編集対象のファイルが見つかりません`n" . "ファイル名:" . the_file } ; ファイルを Emacs に一つだけドロップする PostMessage, 0x233, HDrop(the_file), 0,, ahk_class Emacs sleep, 100 } return } Catch e { MsgBox, % "ファイル指定のエラー`n" . e . "`n" . "プログラムを終了します" ExitApp } } ; ======================================== ; My Scripts ; http://lukewarm.s101.xrea.com/myscripts/ ; ファイルドロップ関数 ; 指定ウィンドウに改行区切りで指定されたファイルをドロップする ; #17 [Make AHK drop files into other applications: post #17] - Posted 19 March 2014 - 07:54 AM ; http://autohotkey.com/board/topic/41467-make-ahk-drop-files-into-other-applications/?p=638376 ; #Include DragDrop.ahk HDrop(fnames,x=0,y=0) { characterSize := 2 fns:=RegExReplace(fnames,"\n$") fns:=RegExReplace(fns,"^\n") hDrop:=DllCall("GlobalAlloc" ,"UInt",0x42 ,"UInt",20+(StrLen(fns)*characterSize)+characterSize*2) p:=DllCall("GlobalLock","UInt",hDrop) NumPut(20, p+0) ;offset NumPut(x, p+4) ;pt.x NumPut(y, p+8) ;pt.y NumPut(0, p+12) ;fNC NumPut(1, p+16) ;fWide p2:=p+20 Loop,Parse,fns,`n,`r { DllCall("RtlMoveMemory" ,"UInt",p2 ,"Str",A_LoopField ,"UInt",StrLen(A_LoopField)*characterSize) p2+=StrLen(A_LoopField)*characterSize + characterSize } DllCall("GlobalUnlock","UInt",hDrop) Return hDrop }