; File:        .emacs
; Author:      Nick Nielsen <nick@nielsenhome.net>
; Time-stamp:  <Last changed Thu Jun 28 11:59:24 by Nicky>
; Created:     Thu Jun 28 08:50:55 2018
; Description: .emacs

;; 3/16/2018: from https://truongtx.me/2013/01/07/emacs-package-manager
;;
;; Emacs is not a package manager, and here we load its package manager:
;; Press M-x, type in list-packages to see all available. To install a package,
;; simply hit return when the cursor is on that package and select install.
(require 'package)
(dolist (source '(("gnu" . "http://elpa.gnu.org/packages/")
                  ("marmalade" . "http://marmalade-repo.org/packages/")
                  ("melpa" . "http://melpa.milkbox.net/packages/")
                  ))
  (add-to-list 'package-archives source t))
(package-initialize)

;; 4/2/2018: from https://truongtx.me/2013/01/07/emacs-package-manager
;;
;;; Required packages
;;; everytime emacs starts, it will automatically check if those packages are
;;; missing, it will install them automatically
(when (not package-archive-contents)
  (package-refresh-contents))
(defvar tmtxt/packages
  '(web-mode emmet-mode flycheck gtags ggtags company tide magit git-gutter ahk-mode helm helm-tramp))
(dolist (p tmtxt/packages)
  (when (not (package-installed-p p))
    (package-install p)))

(require 'magit)
(require 'git-gutter)
(global-set-key (kbd "C-x g") 'magit-status)
(global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)

(require 'flycheck)
(require 'helm)
(require 'helm-config)
(require 'tide)
(global-set-key (kbd "M-x") #'helm-M-x)
(global-set-key (kbd "C-x r b") #'helm-filtered-bookmarks)
(global-set-key (kbd "C-x C-f") #'helm-find-files)
(helm-mode 1)
(global-company-mode 1)
(global-git-gutter-mode 1)
(global-magit-file-mode 1)

(defun loaddotemacs()
  "Loads my .emacs file again."
  (interactive nil)
  (load-file "~/.emacs")
)

;; Allow for quick-and-easy reloading of the .emacs file, for testing.
(global-set-key [(control f1)] 'loaddotemacs)

(setq tide-tsserver-executable "/cygwin64/home/Nicky/.emacs.d/elpa/tide-20180608.239/tsserver/tsserver.js")

;; Files that should be opened automatically in a particular mode:
;;(setq auto-mode-alist (cons '("\\.php$" . c-mode) auto-mode-alist))
(add-to-list 'auto-mode-alist '("\\.php$" . my-setup-php))
(setq auto-mode-alist (cons '("\\.mak$" . makefile-mode) auto-mode-alist))

;;=============================================================================
;; 6/18/2018, from https://github.com/ananthakumaran/tide to enable TypeScript
;; editing for AngularJS web apps.
(require 'web-mode)
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode))
(add-hook 'web-mode-hook
          (lambda ()
            (when (string-equal "tsx" (file-name-extension buffer-file-name))
              (setup-tide-mode))))
;; enable typescript-tslint checker
(flycheck-add-mode 'typescript-tslint 'web-mode)

(require 'web-mode)
(add-to-list 'auto-mode-alist '("\\.jsx\\'" . web-mode))
(add-hook 'web-mode-hook
          (lambda ()
            (when (string-equal "jsx" (file-name-extension buffer-file-name))
              (setup-tide-mode))))
;; configure jsx-tide checker to run after your default jsx checker
(flycheck-add-mode 'javascript-eslint 'web-mode)
;;(flycheck-add-next-checker 'javascript-eslint 'jsx-tide 'append)

(add-hook 'js2-mode-hook #'setup-tide-mode)
;; configure javascript-tide checker to run after your default javascript checker
(flycheck-add-next-checker 'javascript-eslint 'javascript-tide 'append)

;; (use-package tide
;;   :ensure t
;;   :after (typescript-mode company flycheck)
;;   :hook ((typescript-mode . tide-setup)
;;          (typescript-mode . tide-hl-identifier-mode)
;;         (before-save . tide-format-before-save)))

;;=============================================================================

(add-to-list 'load-path "~/emacs")
(setq auto-mode-alist (cons '("dotemacs$" . emacs-lisp-mode) auto-mode-alist))
;(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/")

(require 'tramp)
(setq tramp-default-method "ssh")

; At work, I think autosave might be hanging Emacs in Windows XP.
;; (setq auto-save-default nil)

; Always turn on font lock mode.  Need the pretty colors.
(global-font-lock-mode t)

;; Set up the keyboard so the delete key on both the regular keyboard
;; and the keypad delete the character under the cursor and to the right
;; under X, instead of the default, backspace behavior.
(global-set-key [delete] 'delete-char)
(global-set-key [kp-delete] 'delete-char)

;; Switch to the next/previous buffers using CTLR-TAB and SHIFT-TAB
(global-set-key [\C-tab]   'yic-next-buffer)
(global-set-key [(shift tab)]   'yic-prev-buffer)
(global-set-key [(S-iso-lefttab)]   'yic-prev-buffer)

;; Use the % button to find matching parentheses.  Function defined below.
(global-set-key "%" 'match-paren)

(global-set-key "\M-g" 'goto-line) ;; Alt-g to goto line

;; Create file header prefix
(define-prefix-command 'header-keymap nil "f1 TWC notice, f2 Std Header TWC, f3 Std Header Nielsenhome.net")
(global-set-key [f1] 'header-keymap)

;; File headers for my current company.
(define-key header-keymap [f1] 
  (concat
"// COPYRIGHT_BEGIN
//  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
//
//  Copyright (c) 2009, Cable Television Laboratories, Inc. 
//  <oc-mail@cablelabs.com>
// 
//  This program is free software; you can redistribute it and/or modify 
//  it under the terms of only version 2 of the GNU General Public License
//  as published by the Free Software Foundation.
//
//  This file is distributed in the hope that it will be useful, but 
//  WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
//  General Public License for more details.  (a copy is included 
//  that accompanied this file and can also be found at 
//  https://opencable.dev.java.net/, or write to: the Free Software 
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 
//  MA 02110-1301 USA).
// 
//  Please contact CableLabs if you need additional information or 
//  have any questions.
//  
//       CableLabs
//       858 Coal Creek Cir
//       Louisville, CO 80027-9750
//       303 661-9100
//
//       oc-mail@cablelabs.com
// COPYRIGHT_END
"
))

(defun buildHeader2()
  "builds header2 - standard header with Minim email address."
  (interactive nil)
  (buildHeader "nnielsen@minim.co")
)

(defun buildHeader3()
  "builds header3 - standard header with Nielsenhome.net email address."
  (interactive nil)
  (buildHeader "nick@nielsenhome.net")
)

(defun buildHeader(emailStr)
  "Builds a standard header using whichever comment characters are necessary for the current mode, and using the given email address string."
  (interactive nil)
  (insert (concat
           comment-start " File:        " (buffer-name) comment-end "\n"
           comment-start " Author:      Nick Nielsen <" emailStr ">" comment-end "\n"
           comment-start " Time-stamp:  <>\n"
           comment-start " Created:     " (format-time-string "%a %b %d %H:%M:%S %Y") comment-end "\n"
           comment-start " Description: " (buffer-name) comment-end "\n\n"
           )
          )
  )

(define-key header-keymap [f2] 'buildHeader2)
(define-key header-keymap [f3] 'buildHeader3)

;; the function toggle-hexl is defined below
(global-set-key [f3] 'toggle-hexl)

;; the function dos2unix is defined below
(global-set-key [f4] 'dos2unix)

;; revert-buffer is a built-in emacs command, and set it to the f5 key here.
(global-set-key [f5] 'revert-buffer)

(global-set-key [f6] 'gud-break)   ;; gdb breakpoing
(global-set-key [f7] 'gud-print)   ;; gdb print variable at cursor

(global-set-key [f9] 'gud-next)    ;; gdb next
(global-set-key [f10] 'gud-step)   ;; gdb step
(global-set-key [f11] 'gud-finish) ;; gdb finish current function
(global-set-key [f12] 'gud-cont)   ;; gdb continue

;; Set up additional gtags configuration.
;(global-set-key [(control meta .)] 'gtags-find-rtag)
;(global-set-key [(control meta >)] 'gtags-find-with-grep)
;(global-set-key "\C-cu" 'gtags-update)

;; Preserve middle-mouse paste, since gtags takes over middle mouse button.  Now
;; it will be C-c middle-mouse.
;(global-set-key [(control c)mouse-2] 'comint-insert-clicked-input)

; NOTE: For compiling, use C-x ; RET to go to the first error.Use C-x ` to go 
; to subsquent errors.
(global-set-key [(control f9)] 'compile_nick)
(global-set-key [(control meta shift f9)] 'compileclean_nick)

; Function to toggle between hexl-mode and hexl-mode-exit.
(defun toggle-hexl ()
  (interactive)
  "Toggle between hexl-mode and hexl-mode-exit"
  (if (string= mode-name "Hexl")
      (hexl-mode-exit)
    (hexl-mode))
  )

;;
;; NOTE: If you are using ssh from a cygwin terminal, and you start Emacs, I 
;; have trouble with the backspace key (cygwin passes ^H, while Linux generally
;; expects ^?.  The way to fix this is to add the following to your 
;; .bash_profile on the Linux box to which you are connected.
;;
;;if [ "$TERM" == "cygwin" ] ; then
;;    stty erase ^H
;;fi
;;
;; There are other problems in connecting with Cygwin, because Windows / Cygwin 
;; disallows certain CTRL combinations to be sent.
;;

;; Set the mark using both c-RET and c-SPC because on some terminals (for 
;; instance, cygwin) c-SPC does not come through correctly to the remote
;; machine.  Also set C-M-m just in case.
(global-set-key [(control return)] 'set-mark-command)
(global-set-key [(control space)] 'set-mark-command)
(global-set-key [(control meta m)] 'set-mark-command)

;; This makes it so Emacs displays right away despite font setting changes.  
;; Sometimes without this, I have a long pause at startup, on some X Windows 
;; systems
(modify-frame-parameters nil '((wait-for-wm . nil)))

;; ---------------------------------------------------------------------------
;; Support for global gtags.  You must install global and copy gtags.el to your
;; ~/emacs/ directory.
;; ---------------------------------------------------------------------------
 (add-hook 'c-mode-common-hook
   (lambda ()
     (require 'ggtags)
     (ggtags-mode t)))

(add-hook 'c-mode-hook
  (lambda ()
    (c++-mode)))

(add-hook 'php-mode-hook
          (lambda ()
            (ggtags-mode t)
            (set (make-local-variable 'company-backends)
                 '((php-extras-company company-dabbrev) company-capf company-files))))

;; ---------------------------------------------------------------------------
;; Highlight characters past the 80 column mark.  Needs highlight-80+.el from:
;; http://nschum.de/src/emacs/highlight-80+/
;; ---------------------------------------------------------------------------
(add-hook 'c-mode-common-hook 
  (lambda ()
    (require 'highlight-80+)
    (font-lock-mode t)
    (highlight-80+-mode t)
    )
  )

(add-hook 'text-mode-hook
  (lambda ()
    (require 'highlight-80+)
    (font-lock-mode t)
    (highlight-80+-mode t)
    )
  )

(add-hook 'emacs-lisp-mode-hook
  (lambda ()
    (require 'highlight-80+)
    (font-lock-mode t)
    (highlight-80+-mode t)
    )
  )

(add-hook 'sh-mode-hook
  (lambda ()
    (require 'highlight-80+)
    (font-lock-mode t)
    (highlight-80+-mode t)
    )
  )

; ----------------------------------------------------------------------------
; Integration of psvn.el, acquired from http://www.xsteve.at/prg/emacs/psvn.el
; ----------------------------------------------------------------------------
; I HATE the subversion integration.  It is too slow!!
;(require 'psvn) ;; To start, do a M-x svn-status (Map this operation?)

; ----------------------------------------------------------------------------
; Nick's specific key mappings
; ----------------------------------------------------------------------------
;; Always end a file with a newline
(setq require-final-newline t)

;; Stop at the end of the file, not just add lines
(setq next-line-add-newlines nil)

;; Do not show the splash screen at startup!
(setq inhibit-splash-screen t)

;; Enable wheelmouse support by default
(cond (window-system
       (mwheel-install)
))

;; Ditch the Emacs UI.  The toolbar and menu system takes up valuable screen 
;; real estate
;; (if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1)) ;; I like the scrollbar.
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(if (fboundp 'menu-bar-mode) (menu-bar-mode -1))

;; For very large buffers, font-lock can take a really long time.  Supress font-
;; lock for huge buffers.  This parameter is in?  A value of nil will disable 
;; supression (always fontify whole buffer)
;; (setq font-lock-maximum-size nil)

;; This allows me to set a starting size for my frames when I start up Emacs.
;;(defun framehook(framename)
;;  "Default Frame Hook"
;;  (interactive nil)
;;  (set-frame-height framename 77)
;;  )
;;(add-hook 'create-frame-hook 'framehook)
;;(framehook (selected-frame))
;;(make-frame)


;; 3/16/2018, from https://truongtx.me/2014/07/22/setup-php-development-environment-in-emacs
;; First, you need to install web-mode (via package.el)
(defun my-setup-php ()
  ;; enable web mode
  (web-mode)

  ;; make these variables local
  (make-local-variable 'web-mode-code-indent-offset)
  (make-local-variable 'web-mode-markup-indent-offset)
  (make-local-variable 'web-mode-css-indent-offset)

  ;; set indentation, can set different indentation level for different code type
  (setq web-mode-code-indent-offset 3)
  (setq web-mode-css-indent-offset 2)
  (setq web-mode-markup-indent-offset 3)

  (flycheck-select-checker 'my-php)
  (flycheck-mode t)
  ;;(highlight-80+-mode t)
  (ggtags-mode t)
)

;; 6/8/2018, from https://github.com/ananthakumaran/tide to edit TypeScript in
;; AngularJS web apps.
(defun setup-tide-mode ()
  (interactive)
  (tide-setup)
  (flycheck-mode +1)
  (setq flycheck-check-syntax-automatically '(save mode-enabled))
  (eldoc-mode +1)
  (tide-hl-identifier-mode +1)
  (ggtags-mode t)
  ;; company is an optional dependency. You have to
  ;; install it separately via package-install
  ;; `M-x package-install [ret] company`
  (company-mode +1))

;; aligns annotation to the right hand side
(setq company-tooltip-align-annotations t)

;; formats the buffer before saving
(add-hook 'before-save-hook 'tide-format-before-save)

(add-hook 'typescript-mode-hook #'setup-tide-mode)



;; 3/16/2018, from https://truongtx.me/2014/07/22/setup-php-development-environment-in-emacs
;; 
;; Flycheck already includes config for checking PHP syntax using php command
;; line. However, the checker is limited for using with php-mode and php+mode
;; only. To use it with web-mode, you need to re-define it by yourself.
(flycheck-define-checker my-php
  "A PHP syntax checker using the PHP command line interpreter.

See URL `http://php.net/manual/en/features.commandline.php'."
  :command ("php" "-l" "-d" "error_reporting=E_ALL" "-d" "display_errors=1"
            "-d" "log_errors=0" source)
  :error-patterns
  ((error line-start (or "Parse" "Fatal" "syntax") " error" (any ":" ",") " "
          (message) " in " (file-name) " on line " line line-end))
  :modes (php-mode php+-mode web-mode)
)


(defun compile_nick()
  "Compiles my current project with no other input."
  (interactive nil)
  (compile "cd /cygdrive/c/Projects/eyes-1.0_working/eyes-tct && ./compile_cabletester.sh") 
)

(defun compileclean_nick()
  "Cleans my current project with no other input."
  (interactive nil)
  (compile "make clean")
)

(defun dos2unix()
  "Removes all ^M characters in the current buffer (converts DOS text to UNIX text)"
  (interactive nil)
  (goto-line 1)
  (replace-string "\r" "")
  (goto-line 1)
  )

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(c-basic-offset 3)
 '(c-hanging-braces-alist (quote set-from-style))
 '(c-offsets-alist (quote ((substatement-open . 0))))
 '(c-tab-always-indent t)
 '(c-toggle-hungry-state 1)
 '(case-fold-search t)
 '(column-number-mode t)
 '(fill-column 80)
 '(font-lock-maximum-size 512000)
 '(indent-tabs-mode nil)
 '(line-number-mode t)
 '(package-selected-packages
   (quote
    (helm-tramp git-gutter magit eslint-fix typescript tss tide php-extras company-php company-c-headers company helm-gtags helm emmet-mode flycheck web-mode)))
 '(save-place-mode t nil (saveplace))
 '(show-paren-mode t nil (paren))
 '(tab-width 3)
 '(transient-mark-mode nil)
 '(vc-follow-symlinks t) ; Do not ask me each time if version control should follow a symlink to a file.
 '(user-mail-address "nick@nielsenhome.net"))


(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(default ((t (:background "darkslateblue" :foreground "whitesmoke"))))
 '(font-lock-builtin-face ((t (:foreground "yellow" :weight bold))))
 '(font-lock-comment-face ((((class color)) (:foreground "yellow3"))))
 '(font-lock-constant-face ((((class color) (background dark)) (:foreground "tan" :weight bold))))
 '(font-lock-doc-face ((((class color) (background dark)) (:foreground "green" :bold t))))
 '(font-lock-function-name-face ((((class color) (background dark)) (:foreground "lightsteelblue" :weight bold))))
 '(font-lock-keyword-face ((((class color) (background dark)) (:foreground "orange" :bold t))))
 '(font-lock-negation-face ((((class color) (background dark)) (:foreground "red" :bold t))))
 '(font-lock-reference-face ((((class color) (background dark)) (:foreground "tan" :bold t))))
 '(font-lock-string-face ((((class color) (background dark)) (:foreground "green"))))
 '(font-lock-type-face ((((class color) (background dark)) (:foreground "Violet"))))
 '(font-lock-variable-name-face ((((class color) (background dark)) (:foreground "cyan"))))
 '(highlight ((((type tty) (class color)) (:background "green" :foreground "black")))))

;; ----------------------------------------------------------------------------
;; Function to update my gtags.
;; ----------------------------------------------------------------------------
;(defun gtags-update()
;  "Update the gtags for the current file."
;  (interactive nil)  
;  (shell-command "global -vu")
;  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions found from external sources (original source preserved, if 
;; possible):
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Pulled from sigquit.wordpress.com
;; http://sigquit.wordpress.com/2008/09/14/insert-date-string-dot-emacs/
(defun insert-date-string()
  "Insert a nicely formatted date string."
  (interactive)
  (insert (format-time-string "%a %b %d %H:%M:%S %Y")))
              
;; Prevent accidentally killing emacs. (from dahoiv.net/.emacs)
(global-set-key [(control x) (control c)]
		'(lambda ()
		   (interactive)
		   (if (y-or-n-p-with-timeout "Do you really want to exit Emacs ? " 4 nil)
		       (save-buffers-kill-emacs))))

;; ----------------------------------------------------------------------
;; ----------------------------------------------------------------------
;;     Original yic-buffer.el
;;     From: choo@cs.yale.edu (young-il choo)
;;     Date: 7 Aug 90 23:39:19 GMT
;;
;;     This set of functions allows switching buffers quickly forward and
;;     backward using CTL-TAB and SHIFT-TAB.
;; ----------------------------------------------------------------------

(defun yic-ignore (str)
  (or
   ;;buffers I don't want to switch to 
   (string-match "\\*Buffer List\\*" str)
   (string-match "^TAGS" str)
   (string-match "^\\*Messages\\*$" str)
   (string-match "^\\*Scratch\\*$" str)
   (string-match "^\\*Compile-Log\\*$" str)
   (string-match "^\\*Completions\\*$" str)
   (string-match "^\\*Packages\\*$" str)
   (string-match "^\\*helm" str)
   (string-match "^\\*tramp/" str)
   (string-match "^\\*Help\\*$" str)
   (string-match "^\\*vc\\*$" str)
   (string-match "^magit-" str)
   (string-match "^ " str)

   ;;Test to see if the window is visible on an existing visible frame.
   ;;Because I can always ALT-TAB to that visible frame, I never want to 
   ;;Ctrl-TAB to that buffer in the current frame.  That would cause 
   ;;a duplicate top-level buffer inside two frames.
   (memq str                
         (mapcar 
          (lambda (x) 
            (buffer-name 
             (window-buffer 
              (frame-selected-window x))))
          (visible-frame-list)))
   ))

(defun yic-next (ls)
  "Switch to next buffer in ls skipping unwanted ones."
  (let* ((ptr ls)
         bf bn go
         )
    (while (and ptr (null go))
      (setq bf (car ptr)  bn (buffer-name bf))
      (if (null (yic-ignore bn))        ;skip over
   (setq go bf)
        (setq ptr (cdr ptr))
        )
      )
    (if go
        (switch-to-buffer go))))

(defun yic-prev-buffer ()
  "Switch to previous buffer in current window."
  (interactive)
  (yic-next (reverse (buffer-list))))

(defun yic-next-buffer ()
  "Switch to the other buffer (2nd in list-buffer) in current window."
  (interactive)
  (bury-buffer (current-buffer))
  (yic-next (buffer-list)))
;;end of yic buffer-switching methods
;; ----------------------------------------------------------------------
;; ----------------------------------------------------------------------


;; time-stamps  from http://www.djcbsoftware.nl/dot-emacs.html
;; when there is a "Time-stamp: <>" in the first 10 lines of the file,
;; emacs will write time-stamp information there when saving the file.
;; see the top of this file for an example... 

;; NMN: There is a 1 second delay when I pause, and I can't stand it.  Disabling
;; this for now.
;; NMN: 6/28/2018: Re-enabled - seems to work fine.

(setq 
  time-stamp-active t          ; do enable time-stamps
  time-stamp-line-limit 5     ; check first 3 buffer lines for Time-stamp: <>
  ;time-stamp-format "Last changed %02d-%02m-%04y %02H:%02M:%02S by %L, %u") ; date format
  time-stamp-format "Last changed %3a %3b %02d %02H:%02M:%02S by %u")
(add-hook 'write-file-hooks 'time-stamp) ; update when saving

;; ---------------------------------------------------------------------------
;; NMN: I don't remember where this came from, but it is useful.
;; ---------------------------------------------------------------------------
(defun match-paren (arg)
  "Go to the matching paren if on a paren; otherwise insert %."
  (interactive "p")
  (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
        ((looking-at "\\s\)") (forward-char 1) (backward-list 1))
        (t (self-insert-command (or arg 1)))))

