Skip to content

Commit

Permalink
runtime: implement support for ANSI formatting
Browse files Browse the repository at this point in the history
This is mainly for Figwheel.
  • Loading branch information
darwin committed Oct 7, 2016
1 parent 75aca1c commit 335d1b9
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 4 deletions.
67 changes: 67 additions & 0 deletions src/runtime/dirac/runtime/output.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
(ns dirac.runtime.output
(:require [goog.array :as garray]
[clojure.string :as string]
[dirac.runtime.prefs :refer [get-prefs pref]]))

(def re-split (js/RegExp. "(---<.*?>---)" "g"))
(def re-style (js/RegExp. "---<(.*?)>---"))

; -- marking pass for code snippets -----------------------------------------------------------------------------------------

(def re-code (js/RegExp. "`(.*?)`" "g"))

(defn mark-code [text]
(let [code-style (pref :rich-text-code-style)
reset-style (pref :rich-text-reset-style)]
(.replace text re-code (str "---<" code-style ">---$1---<" reset-style ">---"))))

; -- marking pass for ANSI --------------------------------------------------------------------------------------------------

; we support only a subset of SGR, see https://en.wikipedia.org/wiki/ANSI_escape_code
(def CSI "\u001B\\[")
(def re-ansi (js/RegExp. (str CSI "([0-9;]+)" "m") "g"))

(defn parse-int [v]
(let [res (js/parseInt v 10)]
(if-not (js/isNaN res)
res)))

(defn command-to-style [command]
(let [pref-key (keyword (str "rich-text-ansi-style-" command))]
(pref pref-key)))

(defn ansi-code-to-style [sgr-code]
(let [commands (keep parse-int (.split sgr-code ";"))
sanitized-commands (if (empty? commands) [0] commands)
styles (map command-to-style sanitized-commands)]
(string/join ";" styles)))

(defn mark-ansi [text]
(.replace text re-ansi (fn [match sgr-code]
(str "---<" (ansi-code-to-style sgr-code) ">---"))))

; -- soup preparation -------------------------------------------------------------------------------------------------------

(defn style? [s]
(.test re-style s))

(defn build-format-string [soup]
(string/join (map #(if (style? %) "%c" "%s") soup)))

(defn boil-soup [soup]
(let [* (fn [x]
(if (style? x)
(second (.match x re-style))
x))]
(map * soup)))

; -- public api -------------------------------------------------------------------------------------------------------------

(defn boil-rich-text [text]
(let [marked-text (-> text
mark-code
mark-ansi)
soup (.split marked-text re-split)
format-string (build-format-string soup)
boiled-soup (boil-soup soup)]
(cons format-string boiled-soup)))
33 changes: 33 additions & 0 deletions src/runtime/dirac/runtime/prefs.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
(def default-features [:repl])
(def feature-groups {:all known-features
:default default-features})
(def reset-styles "color:inherit;background-color:none;font-weight:normal;text-decoration:none;font-style:normal")

(def default-prefs
{; you can specify a list/vector of features from known-features or a keyword from feature-groups
Expand All @@ -27,6 +28,38 @@
:context-availability-next-trial-waiting-time 10
:eval-time-limit 10000
:java-trace-header-style "color:red"

:rich-text-enabled true
:rich-text-reset-style reset-styles
:rich-text-code-style "color:#666; background-color:rgba(198, 198, 198, 0.3)"
:rich-text-ansi-style-0 reset-styles
:rich-text-ansi-style-1 "font-weight:bold"
:rich-text-ansi-style-3 "font-style: italic"
:rich-text-ansi-style-4 "text-decoration: underline"
:rich-text-ansi-style-9 "text-decoration: line-through"
:rich-text-ansi-style-22 "font-weight:normal;"
:rich-text-ansi-style-23 "font-style:normal"
:rich-text-ansi-style-24 "text-decoration:none;"
:rich-text-ansi-style-29 "text-decoration:none;"
; foreground colors
:rich-text-ansi-style-30 "color: rgb(0, 0, 0)" ; black
:rich-text-ansi-style-31 "color: rgb(128, 0, 0)" ; red
:rich-text-ansi-style-32 "color: rgb(0, 128, 0)" ; green
:rich-text-ansi-style-33 "color: rgb(128, 128, 0)" ; yellow
:rich-text-ansi-style-34 "color: rgb(0, 0, 128)" ; blue
:rich-text-ansi-style-35 "color: rgb(128, 0, 128)" ; magenta
:rich-text-ansi-style-36 "color: rgb(0, 128, 128)" ; cyan
:rich-text-ansi-style-37 "color: rgb(128, 128, 128)" ; gray
; background colors
:rich-text-ansi-style-40 "background-color: rgba(0, 0, 0, 0.2)" ; black
:rich-text-ansi-style-41 "background-color: rgba(128, 0, 0, 0.2)" ; red
:rich-text-ansi-style-42 "background-color: rgba(0, 128, 0, 0.2)" ; green
:rich-text-ansi-style-43 "background-color: rgba(128, 128, 0, 0.2)" ; yellow
:rich-text-ansi-style-44 "background-color: rgba(0, 0, 128, 0.2)" ; blue
:rich-text-ansi-style-45 "background-color: rgba(128, 0, 128, 0.2)" ; magenta
:rich-text-ansi-style-46 "background-color: rgba(0, 128, 128, 0.2)" ; cyan
:rich-text-ansi-style-47 "background-color: rgba(128, 128, 128, 0.2)" ; gray

:runtime-tag "unidentified"
:nrepl-config nil ; see https://github.com/binaryage/dirac/blob/master/src/nrepl/dirac/nrepl/config.clj
:silence-use-of-undeclared-var-warnings true
Expand Down
15 changes: 11 additions & 4 deletions src/runtime/dirac/runtime/repl.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
(:require [goog.object]
[dirac.runtime.prefs :refer [get-prefs pref]]
[dirac.runtime.bootstrap :refer [bootstrap!]]
[dirac.runtime.output :as output]
[clojure.string :as string]
[goog.object :as gobject]
[goog.labs.userAgent.browser :as ua]))
Expand All @@ -28,7 +29,7 @@
; -- tunneling messages to Dirac DevTools -----------------------------------------------------------------------------------

(defn console-tunnel [method & args]
(.apply (gobject/get js/console method) js/console (into-array args)))
(.apply (gobject/get js/console method) js/console (to-array args)))

(defn dirac-msg-args [name args]
(concat ["~~$DIRAC-MSG$~~" name] args))
Expand Down Expand Up @@ -110,9 +111,15 @@
(when-not (should-silence-error? message)
(error request-id "error" message)))

(defn formatted-log [request-id kind format text]
(if-not (and (= format "rich-text") (pref :rich-text-enabled))
(log request-id kind text)
(let [soup (output/boil-rich-text text)]
(apply log request-id kind soup))))

; -- REPL API ---------------------------------------------------------------------------------------------------------------

(def api-version 5) ; version of REPL API
(def api-version 6) ; version of REPL API

(defn ^:export get-api-version []
api-version)
Expand All @@ -131,14 +138,14 @@
[request-id exception]
(error request-id "exception" exception))

(defn ^:export present-output [request-id kind text]
(defn ^:export present-output [request-id kind format text]
(case kind
"java-trace" (present-java-trace request-id text)
(if-let [warning-msg (detect-and-strip "WARNING:" text)]
(emit-warning! request-id warning-msg)
(if-let [error-msg (detect-and-strip "ERROR:" text)]
(emit-error! request-id error-msg)
(log request-id kind text)))))
(formatted-log request-id kind format text)))))

(defn ^:export postprocess-successful-eval
"This is a postprocessing function wrapping weasel javascript evaluation attempt.
Expand Down

0 comments on commit 335d1b9

Please sign in to comment.