Skip to content
This repository has been archived by the owner on Oct 21, 2022. It is now read-only.

collapsible exceptions added in a new namespace, according to #77 #79

Merged
merged 1 commit into from
Mar 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ By default, \*.cljc files are identified as Clojure files. Thus when you eval, i
Clojure file. If you'd like to eval as a ClojureScript file, run the command `Editor: Set current
editor syntax`, select `ClojureScript` and then eval.

## Clojure(script) error messages
Currently this plugin supports an experimental feature that allows to change the default exception behavior (showing the complete stacktrace) to an expandable version of the same. Some screenshots of the new behavior can be found [here](https://github.com/LightTable/Clojure/issues/77).
To use the new behavior go to ```User behaviors``` and add the following lines :

```Clojure
; for Clojure
[:editor.clj :-lt.plugins.clojure/clj-exception]
[:editor.clj :lt.plugins.clojure.collapsible-exception/clj-expandable-exception]

; for Clojurescript
[:editor.cljs :-lt.plugins.clojure/cljs-exception]
[:editor.cljs :lt.plugins.clojure.collapsible-exception/cljs-expandable-exception]
```

## First ClojureScript Repl

Welcome first time ClojureScript users! Please see [David Nolen's tutorial](https://github.com/swannodette/lt-cljs-tutorial) to get familiar with ClojureScript and comfortable with LightTable's repl. Note while doing that tutorial you were in a namespace. A namespace is necessary for a LightTable repl. Once you have finished the tutorial, create your own ClojureScript project with `lein new mies my-project` and eval there. If you want to add dependencies to your project, read the [below section](#clojurescript-eval) as that requires a different type of LightTable connection.
Expand Down
14 changes: 14 additions & 0 deletions clojure.behaviors
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,18 @@

[:sidebar.docs.search :lt.plugins.clojure/clj-doc-search]
[:sidebar.docs.search :lt.plugins.clojure/cljs-doc-search]

; collapsible stacktrace
[:editor.clj.common :lt.plugins.clojure.collapsible-exception/expandable-exceptions]
; new :collapsible.exception TAG
[:collapsible.exception :lt.objs.menu/menu!]
[:collapsible.exception :lt.objs.eval/ex-menu+]
[:collapsible.exception :lt.objs.eval/ex-clear]
[:collapsible.exception :lt.objs.eval/expand-on-click]
[:collapsible.exception :lt.objs.eval/shrink-on-double-click]
[:collapsible.exception :lt.objs.eval/destroy-on-cleared]
;[:inline.exception :lt.objs.eval/copy-exception]
;NOTE: currently this copies the complete stacktrace but what about just
; copying the summary?
[:collapsible.exception :lt.objs.eval/copy-result]
]
100 changes: 100 additions & 0 deletions src/lt/plugins/clojure/collapsible_exception.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
(ns lt.plugins.clojure.collapsible-exception
(:require [lt.util.dom :as dom]
[lt.object :as object]
[lt.objs.editor :as ed]
[lt.objs.notifos :as notifos]
[crate.binding :refer [bound]])
(:require-macros [lt.macros :refer [defui behavior]]))

(def ^:private ^:const NOT_FOUND -1)

(defn truncate
"truncate a string at newline or at 100 characters long"
[text]
(when-not (empty? text)
(if (= NOT_FOUND (.indexOf text "\n"))
(subs text 0 100); take 100 characters
(first (clojure.string/split-lines text)))))

(defn ->collapse-class [this summary]
(str "inline-exception result-mark"
(when (:open this) " open")))

(defui collapsible-exception-UI [this info]
(let [stacktrace (:result info)
summary (str (:summary info) " ...")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could do a sanity check here and limit to say 100 characters ?

[:span {:class (bound this #(->collapse-class % summary))
:style "background: #73404c; color: #ffa6a6;
max-width:initial; max-height:initial"}
[:span.truncated summary]
[:span.full stacktrace]])
:mousewheel (fn [e] (dom/stop-propagation e))
:click (fn [e] (dom/prevent e)
(object/raise this :click))
:contextmenu (fn [e] (dom/prevent e)
(object/raise this :menu! e))
:dblclick (fn [e] (dom/prevent e)
(object/raise this :double-click)))

(object/object* ::collapsible-exception
:triggers #{:click :double-click :clear!}
:tags #{:inline :collapsible.exception}
:init
(fn [this info]
(when-let [ed (ed/->cm-ed (:ed info))]
(let [content (collapsible-exception-UI this info)]
(object/merge! this (assoc info
:widget (ed/line-widget (ed/->cm-ed (:ed info)) (:line (:loc info))
content, {:coverGutter false})))
content))))

(behavior ::expandable-exceptions
:triggers #{:editor.exception.collapsible}
:reaction
(fn [this summary stack loc]
(let [ed (:ed @this)
line (ed/line-handle ed (:line loc))
ex-obj (object/create ::collapsible-exception
{:ed this, :result stack,
:summary summary
:loc loc, :line line})]
(when-let [prev (get (@this :widgets) [line :inline])]
(when (:open @prev) (object/merge! ex-obj {:open true}))
(object/raise prev :clear!))
(when (:start-line loc)
(doseq [widget (map #(get (@this :widgets) [(ed/line-handle ed %) :inline])
(range (:start-line loc) (:line loc)))
:when widget]
(object/raise widget :clear!)))
(object/update! this [:widgets] assoc [line :inline] ex-obj))))


(behavior ::clj-expandable-exception
:triggers #{:editor.eval.clj.exception}
:reaction (fn [obj res passed?]
(when-not passed?
(notifos/done-working ""))
(let [meta (:meta res)
loc {:line (dec (:end-line meta)) :ch (:end-column meta 0)
:start-line (dec (:line meta 1))}]
(notifos/set-msg! (:result res) {:class "error"})
(object/raise obj :editor.exception.collapsible (:result res) (:stack res) loc))))

(behavior ::cljs-expandable-exception
:triggers #{:editor.eval.cljs.exception}
:reaction (fn [obj res passed?]
(when-not passed?
(notifos/done-working ""))
(let [meta (:meta res)
loc {:line (dec (:end-line meta)) :ch (:end-column meta)
:start-line (dec (:line meta))}
msg (or (:stack res) (truncate (:ex res)))
stack (cond
(:stack res) (:stack res)
(and (:ex res) (.-stack (:ex res))) (.-stack (:ex res))
(and (:ex res) (:verbatim meta)) (:ex res)
(and (:ex res) (not (:verbatim meta))) (pr-str (:ex res))
(not (nil? msg)) (or (:stack res) (:ex res)); untruncated stacktrace
:else "Unknown error")]
(notifos/set-msg! msg {:class "error"})
(object/raise obj :editor.exception.collapsible msg stack loc))))