|
7 | 7 | (:import (javax.swing AbstractListModel BorderFactory JDialog
|
8 | 8 | JFrame JLabel JList JMenuBar JOptionPane
|
9 | 9 | JPanel JScrollPane JSplitPane JTextArea
|
10 |
| - JTextField JTree KeyStroke SpringLayout JTextPane |
| 10 | + JTextField JTree KeyStroke SpringLayout |
| 11 | + JTextPane JCheckBox JButton |
11 | 12 | ListSelectionModel
|
12 | 13 | UIManager)
|
13 | 14 | (javax.swing.event TreeSelectionListener
|
14 | 15 | TreeExpansionListener)
|
15 | 16 | (javax.swing.tree DefaultMutableTreeNode DefaultTreeModel
|
16 | 17 | TreePath TreeSelectionModel)
|
17 | 18 | (java.awt Insets Rectangle Window)
|
18 |
| - (java.awt.event AWTEventListener FocusAdapter |
19 |
| - MouseAdapter WindowAdapter KeyAdapter) |
| 19 | + (java.awt.event AWTEventListener FocusAdapter |
| 20 | + MouseAdapter WindowAdapter |
| 21 | + ActionListener KeyAdapter) |
20 | 22 | (java.awt AWTEvent Color Font GridLayout Toolkit)
|
21 | 23 | (java.net URL)
|
22 | 24 | (java.util.concurrent LinkedBlockingQueue)
|
|
34 | 36 | [clooj.navigate :as navigate]
|
35 | 37 | [clooj.project :as project]
|
36 | 38 | [clooj.indent :as indent]
|
37 |
| - [clooj.style :as style] |
38 | 39 | [clooj.brackets :as brackets]
|
39 | 40 | [clooj.highlighting :as highlighting]
|
40 |
| - [clooj.search :as search]) |
| 41 | + [clooj.search :as search] |
| 42 | + [clooj.settings :as settings]) |
41 | 43 | (:gen-class
|
42 | 44 | :methods [^{:static true} [show [] void]]))
|
43 | 45 |
|
|
72 | 74 | (.setBracketMatchingEnabled false)
|
73 | 75 | (.setAutoIndentEnabled false)
|
74 | 76 | (.setAntiAliasingEnabled true)
|
| 77 | + (.setLineWrap wrap) |
75 | 78 | ))
|
76 | 79 |
|
77 | 80 | (def get-clooj-version
|
|
84 | 87 | URL. slurp read-string (nth 2))
|
85 | 88 | (catch Exception _ nil)))))
|
86 | 89 |
|
87 |
| -;; font |
88 |
| - |
89 |
| -(defonce current-font (atom nil)) |
90 |
| - |
91 |
| -(defn font [name size] |
92 |
| - (Font. name Font/PLAIN size)) |
93 |
| - |
94 |
| -(def default-font |
95 |
| - (cond (utils/is-mac) ["Monaco" 11] |
96 |
| - (utils/is-win) ["Courier New" 12] |
97 |
| - :else ["Monospaced" 12])) |
| 90 | +;; settings |
| 91 | + |
| 92 | +(def default-settings |
| 93 | + (merge |
| 94 | + (zipmap [:font-name :font-size] |
| 95 | + (cond (utils/is-mac) ["Monaco" 11] |
| 96 | + (utils/is-win) ["Courier New" 12] |
| 97 | + :else ["Monospaced" 12])) |
| 98 | + {:line-wrap-doc false |
| 99 | + :line-wrap-repl-out false |
| 100 | + :line-wrap-repl-in false |
| 101 | + :show-only-monospaced-fonts true |
| 102 | + })) |
| 103 | + |
| 104 | +(defn load-settings [] |
| 105 | + (atom |
| 106 | + (merge default-settings |
| 107 | + (utils/read-value-from-prefs utils/clooj-prefs "settings")))) |
| 108 | + |
| 109 | +(defn save-settings [settings] |
| 110 | + (utils/write-value-to-prefs |
| 111 | + utils/clooj-prefs |
| 112 | + "settings" |
| 113 | + settings)) |
| 114 | + |
| 115 | +(defn apply-settings [app settings] |
| 116 | + |
| 117 | + (defn set-line-wrapping [text-area mode] |
| 118 | + (.setLineWrap text-area mode)) |
98 | 119 |
|
99 |
| -(defn set-font |
100 |
| - ([app font-name size] |
101 |
| - (let [f (font font-name size)] |
| 120 | + (defn set-font |
| 121 | + [app font-name size] |
| 122 | + (let [f (Font. font-name Font/PLAIN size)] |
102 | 123 | (utils/awt-event
|
103 |
| - (utils/write-value-to-prefs utils/clooj-prefs "app-font" |
104 |
| - [font-name size]) |
105 | 124 | (dorun (map #(.setFont (app %) f)
|
106 | 125 | [:doc-text-area :repl-in-text-area
|
107 | 126 | :repl-out-text-area :arglist-label
|
108 | 127 | :search-text-area :help-text-area
|
109 |
| - :completion-list])) |
110 |
| - (reset! current-font [font-name size])))) |
111 |
| - ([app font-name] |
112 |
| - (let [size (second @current-font)] |
113 |
| - (set-font app font-name size)))) |
114 |
| - |
115 |
| -(defn load-font [app] |
116 |
| - (apply set-font app (or (utils/read-value-from-prefs utils/clooj-prefs "app-font") |
117 |
| - default-font))) |
| 128 | + :completion-list]))))) |
| 129 | + |
| 130 | + (set-line-wrapping |
| 131 | + (:doc-text-area app) |
| 132 | + (:line-wrap-doc settings)) |
| 133 | + (set-line-wrapping |
| 134 | + (:repl-in-text-area app) |
| 135 | + (:line-wrap-repl-in settings)) |
| 136 | + (set-line-wrapping |
| 137 | + (:repl-out-text-area app) |
| 138 | + (:line-wrap-repl-out settings)) |
118 | 139 |
|
| 140 | + (set-font app |
| 141 | + (:font-name settings) |
| 142 | + (:font-size settings)) |
| 143 | + (reset! (:settings app) settings) |
| 144 | + (save-settings settings)) |
| 145 | + |
| 146 | +;; font |
| 147 | + |
119 | 148 | (defn resize-font [app fun]
|
120 |
| - (let [[name size] @current-font] |
121 |
| - (set-font app name (fun size)))) |
| 149 | + (apply-settings app (update-in @(:settings app) |
| 150 | + [:font-size] |
| 151 | + fun))) |
122 | 152 |
|
123 | 153 | (defn grow-font [app] (resize-font app inc))
|
124 | 154 |
|
125 | 155 | (defn shrink-font [app] (resize-font app dec))
|
126 | 156 |
|
| 157 | + |
127 | 158 | ;; caret finding
|
128 | 159 |
|
129 | 160 | (def highlight-agent (agent nil))
|
|
285 | 316 | (defn make-scroll-pane [text-area]
|
286 | 317 | (RTextScrollPane. text-area))
|
287 | 318 |
|
288 |
| -(defn setup-search-text-area [app] |
| 319 | +(defn setup-search-elements [app] |
| 320 | + (.setVisible (:search-match-case-checkbox app) false) |
| 321 | + (.setVisible (:search-regex-checkbox app) false) |
| 322 | + (doto (:search-close-button app) |
| 323 | + (.setVisible false) |
| 324 | + (.setBorder nil) |
| 325 | + (.addActionListener |
| 326 | + (reify ActionListener |
| 327 | + (actionPerformed [_ _] (search/stop-find app))))) |
289 | 328 | (let [sta (doto (app :search-text-area)
|
290 | 329 | (.setVisible false)
|
291 |
| - (.setBorder (BorderFactory/createLineBorder Color/DARK_GRAY)) |
292 |
| - (.addFocusListener (proxy [FocusAdapter] [] (focusLost [_] (search/stop-find app)))))] |
| 330 | + (.setBorder (BorderFactory/createLineBorder Color/DARK_GRAY)))] |
293 | 331 | (utils/add-text-change-listener sta #(search/update-find-highlight % app false))
|
294 | 332 | (utils/attach-action-keys sta ["ENTER" #(search/highlight-step app false)]
|
295 | 333 | ["shift ENTER" #(search/highlight-step app true)]
|
|
300 | 338 | (.setVisible true)
|
301 | 339 | ))
|
302 | 340 |
|
303 |
| -(defn exit-if-closed [^java.awt.Window f] |
| 341 | +(defn exit-if-closed [^java.awt.Window f app] |
304 | 342 | (when-not @embedded
|
305 | 343 | (.addWindowListener f
|
306 | 344 | (proxy [WindowAdapter] []
|
307 | 345 | (windowClosing [_]
|
| 346 | + (save-caret-position app) |
308 | 347 | (System/exit 0))))))
|
309 | 348 |
|
310 | 349 | (def no-project-txt
|
|
326 | 365 | (select menu <b>File > New...</b>)<br>
|
327 | 366 | 2. edit an existing file by selecting one at left.</html>")
|
328 | 367 |
|
| 368 | +(defn move-caret-to-line [textarea] |
| 369 | + "Move caret to choosen line" |
| 370 | + |
| 371 | + (defn current-line [] |
| 372 | + (inc (.getLineOfOffset textarea (.getCaretPosition textarea)))) |
| 373 | + |
| 374 | + (let [line-str (utils/ask-value "Line number:" "Go to Line") |
| 375 | + line-num (Integer. |
| 376 | + (if (or (nil? line-str) (nil? (re-find #"\d+" line-str))) |
| 377 | + (current-line) |
| 378 | + (re-find #"\d+" line-str)))] |
| 379 | + (utils/scroll-to-line textarea line-num) |
| 380 | + (.requestFocus textarea))) |
329 | 381 |
|
330 | 382 | (defn open-project [app]
|
331 | 383 | (when-let [dir (utils/choose-directory (app :f) "Choose a project directory")]
|
|
369 | 421 | (defn create-app []
|
370 | 422 | (let [doc-text-panel (JPanel.)
|
371 | 423 | doc-label (JLabel. "Source Editor")
|
372 |
| - repl-out-text-area (JTextArea.) |
| 424 | + repl-out-text-area (make-text-area false) |
373 | 425 | repl-out-scroll-pane (repl-output/tailing-scroll-pane repl-out-text-area)
|
374 | 426 | repl-out-writer (repl/make-repl-writer repl-out-text-area)
|
375 | 427 | repl-in-text-area (make-text-area false)
|
|
380 | 432 | completion-list (JList.)
|
381 | 433 | completion-scroll-pane (JScrollPane. completion-list)
|
382 | 434 | search-text-area (JTextField.)
|
| 435 | + search-match-case-checkbox (JCheckBox. "Match case") |
| 436 | + search-regex-checkbox (JCheckBox. "Regex") |
| 437 | + search-close-button (JButton. "X") |
383 | 438 | arglist-label (create-arglist-label)
|
384 | 439 | pos-label (JLabel.)
|
385 | 440 | frame (JFrame.)
|
|
418 | 473 | docs-tree-panel
|
419 | 474 | docs-tree-label
|
420 | 475 | search-text-area
|
| 476 | + search-match-case-checkbox |
| 477 | + search-regex-checkbox |
| 478 | + search-close-button |
421 | 479 | pos-label
|
422 | 480 | repl-out-writer
|
423 | 481 | doc-split-pane
|
|
430 | 488 | ))
|
431 | 489 | doc-text-area (new-doc-text-area app)
|
432 | 490 | doc-scroll-pane (make-scroll-pane doc-text-area)
|
433 |
| - app (assoc app :doc-text-area doc-text-area)] |
| 491 | + app (assoc app :doc-text-area doc-text-area) |
| 492 | + app (assoc app :settings (load-settings))] |
434 | 493 | (doto frame
|
435 | 494 | (.setBounds 25 50 950 700)
|
436 | 495 | (.setLayout layout)
|
|
442 | 501 | (.add doc-label)
|
443 | 502 | (.add pos-label)
|
444 | 503 | (.add search-text-area)
|
445 |
| - (.add arglist-label)) |
| 504 | + (.add arglist-label) |
| 505 | + (.add search-match-case-checkbox) |
| 506 | + (.add search-regex-checkbox) |
| 507 | + (.add search-close-button)) |
446 | 508 | (doto docs-tree-panel
|
447 | 509 | (.setLayout (SpringLayout.))
|
448 | 510 | (.add docs-tree-label)
|
|
471 | 533 | navigate/attach-navigation-keys)
|
472 | 534 | (.setSyntaxEditingStyle repl-in-text-area
|
473 | 535 | SyntaxConstants/SYNTAX_STYLE_CLOJURE)
|
| 536 | + (.setSyntaxEditingStyle repl-out-text-area |
| 537 | + SyntaxConstants/SYNTAX_STYLE_CLOJURE) |
474 | 538 | (.setModel docs-tree (DefaultTreeModel. nil))
|
475 | 539 | (utils/constrain-to-parent split-pane :n gap :w gap :s (- gap) :e (- gap))
|
476 | 540 | (utils/constrain-to-parent doc-label :n 0 :w 0 :n 15 :e 0)
|
477 | 541 | (utils/constrain-to-parent doc-scroll-pane :n 16 :w 0 :s -16 :e 0)
|
478 | 542 | (utils/constrain-to-parent pos-label :s -14 :w 0 :s 0 :w 100)
|
479 |
| - (utils/constrain-to-parent search-text-area :s -15 :w 80 :s 0 :w 300) |
| 543 | + (utils/constrain-to-parent search-text-area :s -15 :w 100 :s 0 :w 350) |
| 544 | + (utils/constrain-to-parent search-match-case-checkbox :s -15 :w 355 :s 0 :w 470) |
| 545 | + (utils/constrain-to-parent search-regex-checkbox :s -15 :w 475 :s 0 :w 550) |
| 546 | + (utils/constrain-to-parent search-close-button :s -15 :w 65 :s 0 :w 95) |
480 | 547 | (utils/constrain-to-parent arglist-label :s -14 :w 80 :s -1 :e -10)
|
481 | 548 | (.layoutContainer layout frame)
|
482 |
| - (exit-if-closed frame) |
483 |
| - (setup-search-text-area app) |
| 549 | + (exit-if-closed frame app) |
| 550 | + (setup-search-elements app) |
484 | 551 | (activate-caret-highlighter app)
|
485 | 552 | (setup-temp-writer app)
|
486 | 553 | (utils/attach-action-keys doc-text-area
|
|
522 | 589 | (.setText doc-label (str "Source Editor \u2014 " (.getPath file)))
|
523 | 590 | (.setEditable text-area true)
|
524 | 591 | (.setSyntaxEditingStyle text-area
|
525 |
| - (let [file-name (.getName file-to-open)] |
| 592 | + (let [file-name (.getName file-to-open)] |
526 | 593 | (if (or (.endsWith file-name ".clj")
|
527 | 594 | (.endsWith file-name ".clj~"))
|
528 | 595 | SyntaxConstants/SYNTAX_STYLE_CLOJURE
|
529 | 596 | SyntaxConstants/SYNTAX_STYLE_NONE))))
|
530 | 597 | (do (.setText text-area no-project-txt)
|
531 | 598 | (.setText doc-label (str "Source Editor (No file selected)"))
|
532 | 599 | (.setEditable text-area false)))
|
533 |
| - (update-caret-position text-area) |
| 600 | + |
534 | 601 | (indent/setup-autoindent text-area)
|
535 | 602 | (reset! (app :file) file)
|
| 603 | + (load-caret-position app) |
| 604 | + (update-caret-position text-area) |
536 | 605 | (repl/apply-namespace-to-repl app)
|
537 | 606 | (reset! changing-file false)))
|
538 | 607 |
|
|
556 | 625 | (def project-clj-text (.trim
|
557 | 626 | "
|
558 | 627 | (defproject PROJECTNAME \"1.0.0-SNAPSHOT\"
|
559 |
| - :description \"FIXME: write\" |
560 |
| - :dependencies [[org.clojure/clojure \"1.3.0\"]]) |
| 628 | + :description \"FIXME: write description\" |
| 629 | + :dependencies [[org.clojure/clojure \"1.5.1\"]]) |
561 | 630 | "))
|
562 | 631 |
|
563 | 632 | (defn specify-source [project-dir title default-namespace]
|
|
690 | 759 | ["Move/Rename" "M" nil #(project/rename-project app)]
|
691 | 760 | ["Remove" nil nil #(remove-project app)])
|
692 | 761 | (utils/add-menu menu-bar "Source" "U"
|
693 |
| - ["Comment-out" "C" "cmd1 SEMICOLON" #(utils/comment-out (:doc-text-area app))] |
694 |
| - ["Uncomment-out" "U" "cmd1 shift SEMICOLON" #(utils/uncomment-out (:doc-text-area app))] |
| 762 | + ["Comment" "C" "cmd1 SEMICOLON" #(utils/toggle-comment (:doc-text-area app))] |
695 | 763 | ["Fix indentation" "F" "cmd1 BACK_SLASH" #(indent/fix-indent-selected-lines (:doc-text-area app))]
|
696 | 764 | ["Indent lines" "I" "cmd1 CLOSE_BRACKET" #(utils/indent (:doc-text-area app))]
|
697 | 765 | ["Unindent lines" "D" "cmd1 OPEN_BRACKET" #(utils/unindent (:doc-text-area app))]
|
698 | 766 | ["Name search/docs" "S" "TAB" #(help/show-tab-help app (help/find-focused-text-pane app) inc)]
|
| 767 | + ["Go to line..." "G" "cmd1 L" #(move-caret-to-line (:doc-text-area app))] |
699 | 768 | ;["Go to definition" "G" "cmd1 D" #(goto-definition (repl/get-file-ns app) app)]
|
700 | 769 | )
|
701 | 770 | (utils/add-menu menu-bar "REPL" "R"
|
|
716 | 785 | ["Go to Project Tree" "P" "cmd1 1" #(.requestFocusInWindow (:docs-tree app))]
|
717 | 786 | ["Increase font size" nil "cmd1 PLUS" #(grow-font app)]
|
718 | 787 | ["Decrease font size" nil "cmd1 MINUS" #(shrink-font app)]
|
719 |
| - ["Choose font..." nil nil #(apply style/show-font-window |
720 |
| - app set-font @current-font)]))) |
| 788 | + ["Settings" nil nil #(settings/show-settings-window |
| 789 | + app apply-settings)]))) |
721 | 790 |
|
722 | 791 |
|
723 | 792 | (defn add-visibility-shortcut [app]
|
|
757 | 826 | (setup-tree app)
|
758 | 827 | (let [tree (app :docs-tree)]
|
759 | 828 | (project/load-expanded-paths tree)
|
760 |
| - (project/load-tree-selection tree)) |
761 |
| - (load-font app))) |
| 829 | + (when (false? (project/load-tree-selection tree)) |
| 830 | + (repl/start-repl app nil))) |
| 831 | + (apply-settings app @(:settings app)))) |
762 | 832 |
|
763 | 833 | (defn -show []
|
764 | 834 | (reset! embedded true)
|
|
0 commit comments