-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcmany.el
More file actions
1194 lines (1088 loc) · 37.7 KB
/
Copy pathcmany.el
File metadata and controls
1194 lines (1088 loc) · 37.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;; cmany.el --- cmany integration for Emacs. -*-coding: utf-8 -*-
;; Copyright (C) 2017 Joao Paulo Magalhaes <dev@jpmag.me>
;; Author: Joao Paulo Magalhaes <dev@jpmag.me>
;; Created: 2017-03-20
;; Version: 0.1
;; Keywords: cmany, Cmake, IDE, Languages, Tools, rtags
;; URL: http://github.com/biojppm/cmany.el
;; This file is not part of GNU Emacs.
;; This file adds facilities to Emacs for interacting
;; with cmany (http://github.com/biojppm/cmany.git ).
;; This extension is licensed under the MIT License.
;;
;; You should have received a copy of the MIT License
;; along with this program. If not, see <http://github.com/biojppm/cmany.el/blob/master/LICENSE.txt
;;; Depends:
;; cmany.el uses facilities from projectile and rtags, if they are
;; available (tested via featurep). These are NOT hard dependencies.
;; cmany.el has the following hard dependencies: term-run
;;; Install:
;; Put this file somewhere on your Emacs-Lisp `load-path' and add the
;; following into your ~/.emacs startup file.
;;
;; <at standards TAB position explain what lisp code is needed>
;; (autoload 'example-install "example" "" t)
;; (autoload 'example-mode "example" "" t)
;;; Commentary:
;; cmany.el provides emacs integration for cmany
;; (http://github.com/biojppm/cmany.git ), a batch-build tool
;; and workflow simplifier for cmake-based projects.
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
(require 'term-run)
;;-----------------------------------------------------------------------------
(defgroup cmany nil
"Customizations for cmany.el."
:prefix "cmany-"
:group 'ide
)
(defcustom cmany-build-dir-prefix "build/"
"the path (relative to the project dir) under which the build
directories should be placed. This applies only to newly created
build trees."
:group 'cmany
:type 'string
:safe #'stringp
)
(defcustom cmany-build-before-run 1
"Whether cmany should build the target before running it."
:group 'cmany
:type 'boolean
:safe #'booleanp
)
(defcustom cmany-rtags-enabled 1
"Whether cmany should announce the current build directory to rtags."
:group 'cmany
:type 'boolean
:safe #'booleanp
)
(defcustom cmany-log-to-messages 1
"Whether cmany should log to the *messages* buffer."
:group 'cmany
:type 'boolean
:safe #'booleanp
)
(defcustom cmany-log-to-buffer 1
"Whether cmany should log to a *cmany* buffer."
:group 'cmany
:type 'boolean
:safe #'booleanp
)
;;-----------------------------------------------------------------------------
(defvar cmany-proj-dir nil
"The directory where the current CMakeLists.txt project is located."
)
(defvar cmany-build-dir nil
"The directory of the current cmany build."
)
(defvar cmany-target ""
"The current active target"
)
(defvar cmany-work-dir nil
"The directory where the current active target should be debugged/run."
)
(defconst cmany-cmd-default "cmany {cmd} -E -c clang++ -X c++11 -t Debug {projdir} {target}"
"The default value for cmany-cmd"
)
(defvar cmany-cmd cmany-cmd-default
"The command form to use when calling cmany."
)
;;-----------------------------------------------------------------------------
(defvar cmany--last-build nil
"The last build command used by cmany."
)
(defvar cmany--last-configure nil
"The last configure command used by cmany."
)
(defvar cmany--last-debug nil
"The last debug command used by cmany."
)
(defvar cmany--current-project nil
""
)
(defvar cmany--with-global-mode nil
""
)
;;-----------------------------------------------------------------------------
(defvar cmany-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c m c") 'cmany-configure)
(define-key map (kbd "C-c m C") 'cmany-configure-with-prompt)
(define-key map (kbd "C-c m b") 'cmany-build)
(define-key map (kbd "C-c m B") 'cmany-build-with-prompt)
(define-key map (kbd "C-c m d") 'cmany-debug)
(define-key map (kbd "C-c m D") 'cmany-debug-with-prompt)
(define-key map (kbd "C-c m r") 'cmany-run)
(define-key map (kbd "C-c m R") 'cmany-run-with-prompt)
(define-key map (kbd "C-c m e") 'cmany-edit-cache)
(define-key map (kbd "C-c m s p") 'cmany-shell-at-proj)
(define-key map (kbd "C-c m s b") 'cmany-shell-at-build)
(define-key map (kbd "C-c m s w") 'cmany-shell-at-work)
(define-key map (kbd "C-c m x ;") 'cmany-switch-proj)
(define-key map (kbd "C-c m x !") 'cmany-restore-or-guess)
(define-key map (kbd "C-c m x ?") 'cmany-wizard)
(define-key map (kbd "C-c m x p") 'cmany-set-proj-dir)
(define-key map (kbd "C-c m x b") 'cmany-set-build-dir)
(define-key map (kbd "C-c m x w") 'cmany-set-work-dir)
(define-key map (kbd "C-c m x t") 'cmany-set-target)
(define-key map (kbd "C-c m x c") 'cmany-set-cmd)
(define-key map (kbd "C-c m A") 'cmany-rtags-announce-build-dir)
map)
"Key map for the Emacs Lisp cmany environment."
)
(easy-menu-define cmany-menu cmany-mode-map
"cmany Mode Menu"
'("cmany"
;;["Documentation" cmany-doc :help "Get documentation for symbol at point"]
;;["Run Tests" cmany-test :help "Run test at point, or all tests in the project"]
["Configure" cmany-configure :keys "C-c m c" :help "call cmany configure"]
["Configure w/prompt" cmany-configure-with-prompt :keys "C-c m C" :help "call cmany configure with interactive prompt for the configure command"]
["Build" cmany-build :keys "C-c m b" :help "call cmany build"]
["Build w/prompt" cmany-build-with-prompt :keys "C-c m B" :help "call cmany build with interactive prompt for the build command"]
["Debug" cmany-debug :keys "C-c m d" :help "open a gdb session with the current target"]
["Debug w/prompt" cmany-debug-with-prompt :keys "C-c m D" :help "open a gdb session with the current target with interactive prompt for the build command"]
["Run" cmany-run :keys "C-c m r" :help "run the current active target"]
["Run w/prompt" cmany-run-with-prompt :keys "C-c m R" :help "run the current active target with interactive prompt for the build command"]
"---"
("Utils"
["rtags: directory" cmany-rtags-announce-build-dir :keys "C-c m A" :help "Announce the cmany build directory to the rtags daemon"]
["Edit cache" cmany-edit-cache :keys "C-c m e" :help "edit the cmake cache of the current project"]
["Open shell: proj dir" cmany-shell-at-proj :keys "C-c m s p" :help "open a shell session at the current project directory"]
["Open shell: build dir" cmany-shell-at-build :keys "C-c m s d" :help "open a shell session at the current build directory"]
["Open shell: work dir" cmany-shell-at-work :keys "C-c m s w" :help "open a shell session at the current work directory"]
)
"---"
("Project params"
["Switch project" cmany-switch-proj :keys "C-c m x ;" :help "Open a previous project"]
["Restore or guess" cmany-restore-or-guess :keys "C-c m x !" :help "Based on the current buffer, restore project parameters from a previous session, or guess if no session exists"]
["Wizard" cmany-wizard :keys "C-c m x ?" :help "Run an interactive prompt sequence to configure the project params"]
["Set project directory" cmany-set-proj-dir :keys "C-c m x p" :help "Set the root of the current project"]
["Set build directory" cmany-set-build-dir :keys "C-c m x b" :help "Set the current build directory"]
["Set target" cmany-set-target :keys "C-c m x t" :help "Set the current target"]
["Set work directory" cmany-set-work-dir :keys "C-c m x w" :help "Set the current work directory"]
["Set command" cmany-set-cmd :keys "C-c m x c" :help "Set the current cmany command"]
)
)
)
;;;###autoload
(define-minor-mode cmany-mode
"cmany.el: simple and batched cmake integration"
:group cmany
:lighter " cmany"
:keymap cmany-mode-map
:after-hook (cmany--mode-hook)
)
;;;###autoload
(define-globalized-minor-mode global-cmany-mode
cmany-mode
(lambda() (cmany--global-mode-hook))
:group 'cmany
:keymap cmany-mode-map
)
(provide 'cmany-mode)
(provide 'global-cmany-mode)
(defun cmany--is-special-buffer (&optional bufname)
(when (not bufname)
(setq bufname (buffer-name (current-buffer)))
)
(or
(and (string-prefix-p "*" bufname) (string-suffix-p "*" bufname))
(and (string-prefix-p " *" bufname) (string-suffix-p "*" bufname))
(string-prefix-p "*magit" bufname)
(eq "COMMIT_EDITMSG" bufname)
)
)
(defun cmany--mode-hook ()
"called every time cmany-mode is set"
;; (message "mode-hook 0")
;; (if cmany--with-global-mode
;; (progn
;; (cmany--log "mode-hook 1")
;; (if (cmany--is-special-buffer)
;; (progn
;; (cmany--log "mode-hook 2.1: ignoring special buffer %s"
;; (buffer-name (current-buffer)))
;; )
;; (progn
;; (cmany--log "mode-hook 2.2: (possibly) restoring from buffer %s"
;; (buffer-name (current-buffer)))
;; (cmany-restore-possibly)
;; )
;; )
;; (cmany--log "mode-hook 4")
;; )
;; (progn
;; (cmany--log "mode-hook 5")
;; (cmany-restore-or-guess)
;; (cmany--log "mode-hook 6")
;; )
;; )
;; (cmany--log "mode-hook 7")
)
(defun cmany--global-mode-hook ()
"called when global-cmany-mode is set"
(setq cmany--with-global-mode t)
(if (cmany--is-special-buffer)
(progn
;;(cmany--log "no, buffer is special: %s"
;; (buffer-name (current-buffer)))
)
(progn
(cmany--log "global cmany-mode? %s (proj-dir=%s)"
(buffer-name (current-buffer))
cmany-proj-dir)
(when (not cmany-proj-dir)
(cmany--log "enabling cmany-mode. current buffer %s" (current-buffer))
(cmany--log " . current file %s" (buffer-file-name))
(cmany-mode 1)
)
)
)
)
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;; utility functions
(defun cmany--log (fmt &rest args)
(if cmany-log-to-messages
(message
(apply 'format
(concat "cmany[%s]: " fmt)
(current-buffer)
args))
)
(if cmany-log-to-buffer
(let ((b (current-buffer)))
(with-current-buffer (get-buffer-create "*cmany*")
;;(end-of-buffer)
(insert
(apply 'format
(concat "cmany[%s]: " fmt "\n")
b args))
)
)
)
)
(defun cmany--visit-buffer (name)
"Create or visit a buffer with the given name."
(when (not (get-buffer name))
(split-window-sensibly (selected-window))
;(other-window 1)
(get-buffer-create name)
;;(term (getenv "SHELL"))
)
(switch-to-buffer-other-window name)
)
(defun cmany--write-to-file (file data)
"http://stackoverflow.com/a/36196312/5875572"
(with-temp-file file
(prin1 data (current-buffer))
)
)
(defun cmany--read-from-file (file symbol)
"http://stackoverflow.com/a/36196312/5875572"
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(let ((v (read (current-buffer))))
;;(cmany--log "symbol: %s: %s" symbol v)
(set symbol v)
)
)
)
(defun cmany--get-cmd-output (workdir cmd)
"Run cmd and return the output in a string if it returns 0;
otherwise return an empty string."
(let ((d default-directory))
(cmany--log "cmd exec: %s" cmd)
(cd workdir)
(with-temp-buffer
(cmany--log "cmd exec dir: %s (was at %s)" (pwd) d)
(let ((p (call-process-shell-command cmd nil (current-buffer))))
(cmany--log "cmd return: %d" p)
(cmany--log "cmd output: %s" (buffer-string))
(if (eq p 0)
(progn (setq -cmcs (buffer-string)))
(progn (setq -cmcs ""))
)
)
)
(cd d)
-cmcs
)
)
(defun cmany--str-not-empty (symbol)
"is there a smarter way to check this?"
(and (boundp symbol)
(not (equal (symbol-value symbol) nil))
(not (string-equal (symbol-value symbol) ""))
)
)
(defun cmany--var-not-nil (symbol)
"is there a smarter way to check this?"
(and (boundp symbol)
(not (equal (symbol-value symbol) nil))
)
)
;;-----------------------------------------------------------------------------
(defun cmany--format-cmd (which-cmd &optional target)
"return a formatted cmany command based on the current proj/build"
;; http://stackoverflow.com/a/17325791/5875572
(let* ((cmd (replace-regexp-in-string (regexp-quote "{cmd}") which-cmd cmany-cmd nil 'literal)))
(setq cmd (replace-regexp-in-string (regexp-quote "{projdir}") cmany-proj-dir cmd nil 'literal))
(when (not target)
(setq target "")
)
(setq cmd (replace-regexp-in-string (regexp-quote "{target}") target cmd nil 'literal))
cmd
)
)
;;-----------------------------------------------------------------------------
(defun cmany--get-cmany-output (cmd &rest more-args)
(let* ((base-cmd (cmany--format-cmd cmd))
(full-cmd (concat base-cmd more-args))
)
;;(cmany--log "cmd base: %s" base-cmd)
;;(cmany--log "cmd full: %s" full-cmd)
(cmany--get-cmd-output cmany-proj-dir full-cmd)
)
)
(defun cmany--get-cmany-lines (cmd &rest more-args)
(let ((out (apply 'cmany--get-cmany-output cmd more-args)))
(split-string out "\n")
)
)
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;; Guessing functions
(defun cmany--guess-proj-dir ()
(let ((r "")
(gotcml nil))
(cmany--log "guess-proj-dir: begin")
;; if projectile is available, turned on, and we're in a project,
;; get the current projectile project root
(when (and
(featurep 'projectile)
(bound-and-true-p projectile-mode)
(projectile-project-p))
(setq r (file-truename (projectile-project-p)))
)
(if (cmany--str-not-empty 'r)
(progn
(cmany--log "guess-proj-dir: after projectile: %s" r)
;; we got project root through projectile
(setq r (file-name-as-directory r))
;; check if there's a CMakeLists.txt there
(if (file-exists-p (concat r "CMakeLists.txt"))
(progn
;; yep, this is what we want
(cmany--log "guess-proj-dir: proj dir from projectile: %s" r)
(setq gotcml t)
)
(progn
(cmany--log "guess-proj-dir: no CMakeLists.txt at proj dir from projectile: %s" r)
)
)
)
(progn
(cmany--log "guess-proj-dir: after projectile: (no dir)")
;; projectile root not available; go up in the fs tree to find CMakeLists.txt
(when (buffer-file-name)
(setq r (locate-dominating-file (buffer-file-name) "CMakeLists.txt"))
(when r
(setq r (file-truename r))
)
)
(if (cmany--str-not-empty 'r)
(progn
;; yep, found a CMakeLists.txt
(cmany--log "guess-proj-dir: proj dir from locate-dominating-file: %s" r)
(setq r (file-name-as-directory r))
(setq gotcml t)
)
(progn
;; otherwise, try the current directory
(when (buffer-file-name)
(setq r (file-name-directory (buffer-file-name)))
)
(if (and r (file-exists-p (concat r "CMakeLists.txt")))
(progn
(cmany--log "guess-proj-dir: proj dir from current dir: %s" r)
(setq gotcml t)
)
(progn
(cmany--log "guess-proj-dir: no CMakeLists.txt at current dir %s" r)
)
)
)
)
)
)
(when (not gotcml)
;; Is r a subdir of any known cmany project?
(dolist (p (cmany--get-known-projects))
(let ((rel (file-relative-name r p)))
(cmany--log "guess-proj-dir: is %s a subdir of %s? %s" r p rel)
(when (not (file-name-absolute-p rel))
(cmany--log "guess-proj-dir: %s is a subdir of %s" r p)
(setq gotcml t)
)
)
)
(when (not gotcml)
(setq r nil)
)
)
(cmany--log "guess-proj-dir: end %s" r)
r ;; return the result
)
)
(defun cmany--get-default-proj-dir ()
(if (cmany--str-not-empty 'cmany-proj-dir)
;; if there's a current cmany-proj-dir, use it
(progn
(cmany--log "cmany-proj-dir already defined: %s" cmany-proj-dir)
cmany-proj-dir)
;; otherwise, make a guess
(cmany--guess-proj-dir)
)
)
(defun cmany--guess-build-dir ()
(interactive)
(let* ((bds (cmany--get-cmany-lines "show_build_dirs")) ;; extract the list of current builds
(bd (car bds)) ;; pick the first
)
(setq bd (file-truename bd))
(cmany--log "build directory guess: %s" bd)
(file-name-as-directory bd)
)
)
(defun cmany--work-dir-or-default ()
(if (cmany--str-not-empty 'cmany-work-dir)
cmany-work-dir
cmany-build-dir
)
)
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;; Prompting functions
(defun cmany--exec-prompt-proj-dir ()
(interactive)
(let* ((prompt "cmany proj dir: ")
(dn (file-name-directory
(let* (pdg (cmany--get-default-proj-dir))
(if pdg
(progn (cmany--log "using guessed %s for proj dir prompt" pdg) pdg)
(progn (cmany--log "using current %s for proj dir prompt" (file-name-directory buffer-file-name))
(file-name-directory buffer-file-name)))
)))
(bn (file-name-base dn))
(result (ido-read-directory-name prompt dn bn nil bn))
)
(setq result (file-truename result))
(cmany--log "prompt for %s%s" prompt result)
(file-name-as-directory result)
)
)
(defun cmany--exec-prompt-build-dir ()
(interactive)
(let* ((prompt "cmany build dir: ")
(dn (file-name-directory (cmany--guess-build-dir)))
(bn (file-name-base dn))
(result (ido-read-directory-name prompt dn bn nil bn))
)
(setq result (file-truename result))
(cmany--log "prompt for %s%s" prompt result)
(file-name-as-directory result)
)
)
(defun cmany--exec-prompt-work-dir ()
(interactive)
(let* ((prompt "cmany work dir: ")
(dn (file-name-directory (cmany--work-dir-or-default)))
(bn (file-name-base dn))
(result (ido-read-directory-name prompt dn bn nil bn))
)
(setq result (file-truename result))
(cmany--log "prompt for %s%s" prompt result)
(file-name-as-directory result)
)
)
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;; RTags
;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Asynchronous-Processes.html
(defun cmany-rtags-start ()
"start the rtags daemon"
(interactive)
(when (and cmany-rtags-enabled (featurep 'rtags))
;;(if (not (boundp 'cmany--rtags-rdm))
;; (progn
;; (cmany--log "starting rdm")
;; (setq cmany--rtags-rdm (start-process "cmany-rtags-rdm" "*RTags Log*" "rdm")))
;; (progn (cmany--log "rdm is already running")))
;;)
(rtags-start-process-unless-running)
)
)
(defun cmany-rtags-announce-build-dir (&optional dir)
(interactive
(list (if cmany-rtags-enabled
(ido-read-directory-name "build dir: " cmany-build-dir)
""
)
)
)
(when (and cmany-rtags-enabled (featurep 'rtags))
(cmany-rtags-start)
(start-process (concat "cmany-rtags-rc" " " dir) "*RTags Log*" "rc" "-J" dir)
)
)
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;; Config functions
;;;###autoload
(defun cmany-load-configs ()
"loads configs"
(interactive)
(let ((fn (concat user-emacs-directory "cmany.save")))
(if (file-exists-p fn)
(progn
(cmany--log "loading configs from %s" fn)
(cmany--read-from-file fn 'cmany--configs)
;(message "cmany loaded configs: %s" cmany--configs)
)
(progn
(cmany--log "configs file not found: %s" fn)
(cmany--log "starting with empty config")
(setq cmany--configs ())
)
)
(cmany--get-known-projects)
)
)
;;;###autoload
(defun cmany-load-configs-if-none ()
"loads configs if they are not yet available"
(interactive)
(when (not (cmany--var-not-nil 'cmany--configs))
(cmany-load-configs)
)
)
;;;###autoload
(defun cmany-save-configs ()
(interactive)
(cmany-load-configs-if-none)
(when (not (boundp 'cmany--configs))
(setq cmany--configs ())
)
(let ((pd (file-truename cmany-proj-dir))
(pc
`(("cmany-build-dir" . ,cmany-build-dir)
("cmany-target" . ,cmany-target)
("cmany-cmd" . ,cmany-cmd)
("cmany-work-dir" . ,cmany-work-dir)
("cmany--last-configure" . ,cmany--last-configure)
("cmany--last-build" . ,cmany--last-build)
("cmany--last-debug" . ,cmany--last-debug)
)
)
(tmp ()) ;; we'll put the new list here
)
(add-to-list 'tmp (cons pd pc)) ;; put the new config in first place
(dolist (c cmany--configs)
(when (not (string-equal (car c) pd))
(add-to-list 'tmp c) ;; add more configs if they're not the same
)
)
(setq cmany--configs tmp) ;; done
)
(cmany--write-to-file
(concat user-emacs-directory "cmany.save")
cmany--configs)
(setq cmany--known-projects ())
(cmany--get-known-projects)
)
;;;###autoload
(defun cmany-restore-config (dir)
(interactive
(list
(file-name-as-directory
(ido-read-directory-name "cmake proj dir to restore: " (cmany--guess-proj-dir)))))
(cmany--log "restore-config: begin: %s" dir)
(if (and dir (boundp 'cmany--configs))
(progn
(cmany--log "restore-config: configs available")
(setq dir (file-truename dir))
(let ((c (cdr (assoc dir cmany--configs))))
(if c
(progn
(cmany--log "restore-config: found config for %s: %s" dir c)
;; does the build dir still exist?
(let ((prev-build-dir (cdr (assoc "cmany-build-dir" c))))
(if (not (file-exists-p prev-build-dir))
(progn
(cmany--log "restore-config: cmany-build-dir not found: %s"
prev-build-dir)
)
(progn
(cmany-set-proj-dir dir t)
(cmany-set-build-dir (cdr (assoc "cmany-build-dir" c)) t)
(cmany-set-target (cdr (assoc "cmany-target" c)) t)
(cmany-set-cmd (cdr (assoc "cmany-cmd" c)) t)
(cmany-set-work-dir (cdr (assoc "cmany-work-dir" c)) t)
(setq cmany--last-configure (cdr (assoc "cmany--last-configure" c)))
(setq cmany--last-build (cdr (assoc "cmany--last-build" c)))
(setq cmany--last-debug (cdr (assoc "cmany--last-debug" c)))
(cmany--log "restore-config: end. found config for %s" dir)
t ;; return true to signal loaded config
)
)
)
)
(progn
(cmany--log "restore-config: end. no config was found for %s" dir)
nil ;; no config was found for this dir
)
)
)
)
(progn
(when (not dir)
(cmany--log "restore-config: end. no dir with CMakeLists.txt was found")
)
(when (not (boundp 'cmany--configs))
(cmany--log "restore-config: end. no configs available")
)
nil ;; no configs are available
)
)
)
(defun cmany--clear-last-commands ()
"clears the last stored commands. call whenever a build param changes."
(setq cmany--last-build "")
(setq cmany--last-configure "")
(setq cmany--last-debug "")
)
(defun cmany--get-known-projects ()
(when (or (not (boundp 'cmany--known-projects))
(not cmany--known-projects))
(setq cmany--known-projects (list))
(when (boundp 'cmany--configs)
(dolist (p cmany--configs)
(add-to-list 'cmany--known-projects (car p))
)
)
)
cmany--known-projects
)
;;-----------------------------------------------------------------------------
;;;###autoload
(defun cmany-switch-proj ()
(interactive)
(let ((p (ido-completing-read "choose a project: " (cmany--get-known-projects))))
(when p (cmany-restore-config p))
)
)
;;;###autoload
(defun cmany-set-proj-dir (&optional dir no-save)
"set the project dir used by cmany"
(interactive
(list (call-interactively 'cmany--exec-prompt-proj-dir)
nil))
(cmany--log "set proj dir: %s" dir)
(setq cmany-proj-dir dir)
(cmany--clear-last-commands)
(when (not no-save)
(cmany-load-configs-if-none)
(cmany-save-configs)
)
)
;;;###autoload
(defun cmany-set-build-dir (&optional dir no-save)
"set the build dir used by cmany"
(interactive
(list (call-interactively 'cmany--exec-prompt-build-dir)
nil))
(cmany--log "set build dir: %s" dir)
(setq cmany-build-dir dir)
(cmany--clear-last-commands)
(when (not no-save)
(cmany-load-configs-if-none)
(cmany-save-configs)
)
(cmany-rtags-announce-build-dir cmany-build-dir)
)
;;;###autoload
(defun cmany-set-cmd (&optional cmd no-save)
"set the cmany command form"
(interactive
(list (read-string "cmany command: " cmany-cmd)
nil))
(cmany--log "set command: %s" cmd)
(setq cmany-cmd cmd)
(cmany--clear-last-commands)
(when (not no-save)
(cmany-load-configs-if-none)
(cmany-save-configs)
)
)
;;;###autoload
(defun cmany-set-target (&optional tgt no-save)
"set the current active target for building and running/debugging"
(interactive
(list (ido-completing-read
"cmany current target: "
(cmany--get-cmany-lines "show_targets") nil nil cmany-target)
nil))
(cmany--log "set target: %s" tgt)
(setq cmany-target tgt)
(cmany--clear-last-commands)
(when (not no-save)
(cmany-load-configs-if-none)
(cmany-save-configs)
)
)
;;;###autoload
(defun cmany-set-work-dir (&optional dir no-save)
"set the work directory for the current active target"
(interactive
(list (call-interactively 'cmany--exec-prompt-work-dir)
nil))
(cmany--log "set work dir: %s" dir)
(setq cmany-work-dir dir)
(cmany--clear-last-commands)
(when (not no-save)
(cmany-load-configs-if-none)
(cmany-save-configs)
)
)
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;;-----------------------------------------------------------------------------
;;;###autoload
(defun cmany-configure-with-prompt (cmd)
(interactive
(list
(read-string
"enter configure cmd: "
(if (cmany--str-not-empty 'cmany--last-configure)
(progn cmany--last-configure)
(progn (cmany--format-cmd "configure"))
)
)))
(setq cmany--last-configure cmd)
(cmany-save-configs)
(let ((d default-directory))
(cd cmany-proj-dir)
(compile cmd)
(cd d)
)
)
;;;###autoload
(defun cmany-configure()
(interactive)
(if (cmany--str-not-empty 'cmany--last-configure)
(cmany-configure-with-prompt cmany--last-configure)
(call-interactively 'cmany-configure-with-prompt)
)
)
;;-----------------------------------------------------------------------------
;;;###autoload
(defun cmany-build-with-prompt (cmd)
"build the current target"
(interactive
(list
(read-string
"enter build cmd: "
(if (cmany--str-not-empty 'cmany--last-build)
(progn cmany--last-build)
(progn (cmany--format-cmd "build" cmany-target))
)
)))
(setq cmany--last-build cmd)
(cmany-save-configs)
(let ((d default-directory))
(cd cmany-proj-dir)
(compile cmd)
(cd d)
)
)
;;;###autoload
(defun cmany-build()
(interactive)
(if (cmany--str-not-empty 'cmany--last-build)
(cmany-build-with-prompt cmany--last-build)
(call-interactively 'cmany-build-with-prompt)
)
)
;;-----------------------------------------------------------------------------
;;;###autoload
(defun cmany-debug-with-prompt (cmd &optional workdir)
"debug the current target"
(interactive
(list
(read-string
"enter gdb cmd: "
(if (cmany--str-not-empty 'cmany--last-debug)
(progn cmany--last-debug)
(progn (format "gdb -i=mi %s" (concat cmany-build-dir cmany-target)))
)
)
(let* ((def (cmany--work-dir-or-default))
(dn (file-name-directory def))
(bn (file-name-base def)))
(ido-read-directory-name "work dir: " dn bn nil bn)
)
)
)
(setq cmany--last-debug cmd)
(cmany-save-configs)
(if (not workdir)
(setq workdir cmany-build-dir))
(if cmany-build-before-run
(progn
(setq cmany--dbg-work-dir workdir)
(setq cmany--dbg-cmd cmd)
;; WTF??? when this is uncommented our function never gets called.
;; gotta learn why.
;;(setq cmany--dbg-old-fn (symbol-function compilation-exit-message-function))
(setq compilation-exit-message-function 'cmany--dbg-after-compile)
(compile (concat "cd " cmany-proj-dir " ; " (cmany--format-cmd "build" cmany-target)))
;;(setq compilation-exit-message-function cmany--dbg-old-fn)
)
(progn
(let ((d default-directory))
(cd workdir)
(call-interactively (gdb cmpcmd))
(cd d)
)
)
)
)
(defun cmany--dbg-after-compile (status code msg)
(cmany--log "compilation finished with status %s" status)
(cmany--log "compilation finished with code %d" code)
(cmany--log "compilation finished with msg %s" msg)
(if (and (eq status 'exit) (zerop code))
(progn
(let ((d default-directory))
(when (not (equal d cmany--dbg-work-dir))
(cmany--log "changing to directory %s" cmany--dbg-work-dir)
)
(cd cmany--dbg-work-dir)
(gdb cmany--dbg-cmd)
(when (not (equal d cmany--dbg-work-dir))
(cmany--log "returning to directory %s" d)
)
(cd d)
)
)
(progn
(tooltip-show "\n :-( \n\nCompilation failed.\n"))
)
)
;;;###autoload
(defun cmany-debug()
(interactive)
(if (cmany--str-not-empty 'cmany--last-debug)
(cmany-debug-with-prompt cmany--last-debug)
(call-interactively 'cmany-debug-with-prompt)
)
)
;;-----------------------------------------------------------------------------
;;;###autoload
(defun cmany-run-with-prompt (cmd &optional workdir)
"run the current target"
(interactive
(list
(read-string
"enter cmd: "
(if (cmany--str-not-empty 'cmany--last-run)
(progn cmany--last-run)
(progn (concat cmany-build-dir cmany-target))
)