1. (defun js-fix-spacing-line ()
  2.   (interactive)
  3.   (let ((current (char-after))
  4.     (next (char-after 1))
  5.     (old-point (point))
  6.     (postfix)
  7.     (difference 0))
  8.     (labels
  9.     ((incf-dif
  10.       ()
  11.       (when (< 0 (+ difference (- old-point (point))))
  12.         (incf difference))
  13.       (insert " "))
  14.      (js-face
  15.       (&optional (pos (point)))
  16.       (get-char-property pos 'face)))
  17.       (beginning-of-line)
  18.       (while (not (eolp))
  19.     (setf current (char-after (1- (point)))
  20.           next (char-after))
  21.     (cond
  22.      ((or (char-equal current ?\ )
  23.           (char-equal current ?\t)
  24.           (char-equal next ?\ )
  25.           (char-equal next ?\t)))
  26.      ((and (equal (js-face (1- (point))) 'font-lock-string-face)
  27.            (equal (js-face) 'font-lock-string-face)))
  28.      ((and (equal (js-face (1- (point))) 'font-lock-comment-face)
  29.            (equal (js-face) 'font-lock-comment-face)))
  30.      ((and (equal (js-face (1- (point))) 'font-lock-keyword-face)
  31.            (not (equal (js-face)
  32.                'font-lock-keyword-face))
  33.            (not (position current " \t")))
  34.       (incf-dif))
  35.      ((position next "=/|&%?><*^:}")
  36.       (when (or (not (position current "=!&|*+-^><")) postfix)
  37.         (setf postfix nil)
  38.         (incf-dif)))
  39.      ((position current "?:,{});,")
  40.       (unless (char-equal next ?\;)
  41.         (unless (and (char-equal current ?})
  42.              (or (char-equal next ?\,)
  43.                  (char-equal next ?\))))
  44.           (unless (and (char-equal current ?\))
  45.                (or (char-equal next ?\))
  46.                    (char-equal next ?\.)
  47.                    (char-equal next ?\,)
  48.                    (char-equal next ?\[)))
  49.         (incf-dif)))))
  50.      ((char-equal current ?=)
  51.       (unless (position next "=")
  52.         (incf-dif)))
  53.      ((position current "<>&|*/%^")
  54.       (unless (and (char-equal next ?=)
  55.                (and (char-equal current ?&)
  56.                 (char-equal next ?&))
  57.                (and (char-equal current ?|)
  58.                 (char-equal next ?|)))
  59.         (incf-dif)))
  60.      ((position next "!~")
  61.       (unless (position current "([")
  62.         (incf-dif)))
  63.      ((char-equal next ?+)
  64.       (cond
  65.        ((char-equal current ?+))
  66.        ((char-equal (char-after (1+ (point))) ?+)
  67.         (if (looking-at ".\\+\\+\\(\\sw\\|\\s_\\|\\s(\\)")
  68.         (incf-dif)
  69.           (setf postfix t)))
  70.        ((char-equal (char-after (1+ (point))) ?=)
  71.         (setf postfix nil)
  72.         (incf-dif))
  73.        ((looking-at "[=><?;/&%*,|:-]\\|\\s(")
  74.         (setf postfix nil)
  75.         (incf-dif))
  76.        (t (incf-dif)
  77.           (setf postfix t))))
  78.  
  79.      ((char-equal current ?+)
  80.       (unless (or (char-equal next ?\+) (char-equal next ?\=))
  81.         (when postfix
  82.           (incf-dif)
  83.           (setf postfix nil))))
  84.  
  85.      ((char-equal next ?-)
  86.       (cond
  87.        ((char-equal current ?-))
  88.        ((char-equal (char-after (1+ (point))) ?-)
  89.         (if (looking-at ".\\-\\-\\(\\sw\\|\\s_\\|\\s(\\)")
  90.         (incf-dif)
  91.           (setf postfix t)))
  92.        ((char-equal (char-after (1+ (point))) ?=)
  93.         (setf postfix nil)
  94.         (incf-dif))
  95.        ((looking-at "[=><?;/&%*,|:+]\\|\\s(")
  96.         (setf postfix nil)
  97.         (incf-dif))
  98.        (t (incf-dif)
  99.           (setf postfix t))))
  100.  
  101.      ((char-equal current ?-)
  102.       (unless (or (char-equal next ?\-) (char-equal next ?\=))
  103.         (when postfix
  104.           (incf-dif)
  105.           (setf postfix nil)))))
  106.     (forward-char)))
  107.     (goto-char (+ old-point difference))))
  108.  
  109. (add-hook
  110.  'js-mode-hook
  111.  (lambda ()
  112.    (local-set-key (kbd "C-x SPC") 'js-fix-spacing-line)))