Help us understand the problem. What is going on with this article?

Google ChromeのテキストエリアをEmacsで編集する'Edit with Emacs'から任意のエディタを起動するデーモンをGo 1.4 for Windowsで書いてみたわけだが、エディタがブラウザの後ろに出てしまってダメかもしれない

More than 3 years have passed since last update.

どういう経緯か忘れたのですが

という記事を拝見しました。概要としては

  • Google Chrome は Firefox とは違い、外部プロセスを起動することは禁止されている
  • そこで Chrome Extension の Edit with Emacs は、Emacs のサービスを 127.0.0.1:9292 に立ち上げて、XMLHttpRequest を使って、テキストエリアの内容を Emacs と交換している。
  • 上記の記事では、Emacs のサーバーのかわりに Perl でサービスを立ち上げて、任意のエディターを Chrome で使えるようにしている

という感じです。記事の方法だと Perl 一式が必要だし、Linux でしか動作が検証されていないようでした(別に Windows で動かないとは書いてないが)。が、記事のおかげで原理はだいたい分かったので、勉強がてら Go 1.4 for Windows で「だいたい同じもの」を作ってみました。

editsrv.go
package main

import (
    "bufio"
    "fmt"
    "html"
    "io"
    "io/ioutil"
    "net/http"
    "os"
    "os/exec"
    "strings"
)

func HasHtml(headers map[string][]string) bool {
    xurl, ok := headers["X-Url"]
    if !ok || len(xurl) <= 0 {
        return false
    }
    return strings.HasPrefix(xurl[0], "https://twitter.com")
}

func typeHeaders(h map[string][]string, w io.Writer) {
    for key, vals := range h {
        for _, val := range vals {
            fmt.Fprintf(w, "%s: %s\n", key, val)
        }
    }
}

func html2text(out io.Writer, in io.Reader) {
    scanner := bufio.NewScanner(in)
    for scanner.Scan() {
        line := scanner.Text()
        fmt.Fprintln(os.Stderr, line)
        line = strings.TrimSpace(line)
        line = strings.Replace(line, "<div><br></div>", "\n", -1)
        line = strings.Replace(line, "<div>", "", -1)
        line = strings.Replace(line, "</div>", "\n", -1)
        line = html.UnescapeString(line)
        io.WriteString(out, line)
    }
}

func text2html(out io.Writer, in io.Reader) {
    scanner := bufio.NewScanner(in)
    for scanner.Scan() {
        line := scanner.Text()
        line = strings.TrimSpace(line)
        line = html.EscapeString(line)
        if line == "" {
            line = "<br>"
        }
        fmt.Fprintf(out, "<div>%s</div>", line)
    }
}

func handler(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(os.Stderr, "From: %s\n", req.RemoteAddr)
    typeHeaders(req.Header, os.Stderr)
    tmpfd, tmpfdErr := ioutil.TempFile("", "editsrv")
    if tmpfdErr != nil {
        fmt.Fprintln(os.Stderr, tmpfdErr)
        return
    }
    io.WriteString(tmpfd, "\xEF\xBB\xBF")
    tmpName := tmpfd.Name()
    defer os.Remove(tmpName)

    hasHtml := HasHtml(req.Header)
    if hasHtml {
        html2text(tmpfd, req.Body)
    } else {
        io.CopyN(tmpfd, req.Body, req.ContentLength)
    }
    tmpfd.Close()

    var editorName string
    if len(os.Args) >= 2 {
        editorName = os.Args[1]
    } else {
        editorName = "notepad.exe"
    }
    editorArgs := make([]string, 0, len(os.Args))
    for i := 2; i < len(os.Args); i++ {
        editorArgs = append(editorArgs, os.Args[i])
    }
    editorArgs = append(editorArgs, tmpName)
    cmd1 := exec.Command(editorName, editorArgs...)
    fmt.Fprintf(os.Stderr, "Call %s ", editorName)
    for _, arg1 := range editorArgs {
        fmt.Fprintf(os.Stderr, " %s", arg1)
    }
    fmt.Fprint(os.Stderr, "\n")
    if err := cmd1.Run(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
    tmpfd, tmpfdErr = os.Open(tmpName)
    if tmpfdErr != nil {
        fmt.Fprintln(os.Stderr, tmpfdErr)
        tmpfd.Close()
        return
    }
    fmt.Fprintf(os.Stderr, "Send '%s' to Chrome\n", tmpName)
    if hasHtml {
        text2html(w, tmpfd)
    } else {
        _, copyErr2 := io.Copy(w, tmpfd)
        if copyErr2 != nil {
            fmt.Fprintln(os.Stderr, copyErr2)
        }
    }
    tmpfd.Close()
    fmt.Fprintln(os.Stderr, "Done")
}

func main() {
    fmt.Println("Any Editor Server for chrome-extension 'Edit with Emacs'")
    http.HandleFunc("/edit", handler)
    http.ListenAndServe(":9292", nil)
}

最初、よー分からんで何故か TCP のレベルからやろうとして挫折したのですが、net/http で書き直したところ、比較的簡単に出来ました。「editsrv.exe gvim.exe」を走らせておくと、テキストエリアの右下に出る edit のマークをクリックした時に gvim.exe が起動するようになります。(なお、UTF8 対応エディターである必要があります)

ただ、twitter の本家サイトについては、テキストエリアの内容が何故か HTML で飛んでくるので、このサイトだけは特別扱いして、HTML ⇔ プレーンテキストの変換を相互にやってます。やりすぎかな

普通、この手のものは「思いついたのはいいが、なかなかうまいこと作れない」ものなんですが、自分にしては、あっさりできて驚きでした。ま、多分、似たようなものの Go 版は先人がとっくの昔に作ってそうではありますが…まぁ、手段が目的みたいなもんですから、そこんところは目をつぶってくださいませ。

しかし…起動したエディターがブラウザの後ろに隠れてしまうのはどうしたもんかな…

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away