Red Hot Chili Python

Мой .emacs

«  Заголовок окна в емаксе   ::   Contents   ::   Экспортирование из PostgreSQL в MongoDB  »

Мой .emacs

Warning

Этот пост находится в процессе написания. Прошу его не читать. Когда я закончу – пост попадёт в вашу рсс-ленту (и я наверняка напишу о нём на всякие хабры).

Note

Эта заметка – бесконечна. По мере необходимости я буду редактировать и дополнять её.

Любой уважающий себя пользователь emacs должен написать рано или поздно свою заметку с описанием своего файла ~/.emacs. Буду и я потихоньку писать сюда, а какой-то более-менее оконечный вид заметка приобретет – сделаю релиз.

Todo

Сделать большое вступление, где описываются прелести емакса.

Цветовая схема и шрифт

Первое, что бросается в глаза – цветовая схема и шрифт. В качестве шрифта я использую Consolas 10 (да да, производства Microsoft):

(set-frame-font "-microsoft-Consolas-normal-normal-normal-*-13-*-*-*-m-0-iso10646-1")

Ну а цветовая схема – когда-то найденная на просторах интернета. Она несложная и в ней наверняка есть какие-то недоделки (к примеру, в rst-mode у заголовков слишком яркий фон):

;;;;; Цвета
(setq default-frame-alist
      '( ;;(cursor-color . "Firebrick")
        (cursor-color . "White")
        (cursor-type . box)
        ;;(foreground-color . "White")
        ;;(background-color . "DarkSlateGray")
        (foreground-color . "White")
        (background-color . "Black")
        (vertical-scroll-bars . right)))

Поиск файла по всему проекту

Понятная задача – открыть файл product.py где-то в проекте. Чего хочется – тоже понятно: нажать какое-то сочетание клавиш и набрать product.py, выбрать нужный и нажать ентер.

Попробовав разное скажу сразу, что идеальным для меня оказался проект fuzzy-find-in-project. Написан он на руби (ну, с кем не бывает) и делает именно то, что нужно.

Сначала вы вызываете команду fuzzy-find-project-root и говорите, где находится корневая папка проекта. Затем вы вызываете fuzzy-find-in-project для того самого поиска по всему проекту.

Перемещаться по найденным файлам стоит через C-n/C-p (а не стрелочками).

Я себе забиндил fuzzy-find-in-project на C-x g:

;;;; fuzzy find in project
(require 'fuzzy-find-in-project)
(fuzzy-find-project-root "~/workspace/live-i18n/")
(global-set-key [?\C-x ?\g]  'fuzzy-find-in-project)

Todo

Описать установку

Управление проектами

Собственно, для каждого проекта лень делать fuzzy-find-in-project или еще что подобное (к примеру, rope-open-project), потому нашел отличное решение – project-local-variables. Простое решение как столб (такое я и люблю). Вы кладёте файл .emacs-project в корень проекта, и, чтоб открыть проект, просто открываете этот файл, а он автоматом исполняется. А в нём уже вы делаете, к примеру, следующее (rope я сейчас не использую, потому соответствующая строка у меня закомментирована):

(fuzzy-find-project-root (file-name-directory load-file-name))
(rope-open-project (file-name-directory load-file-name))

Todo

Описать установку

Переход к линии

Маленькие хауту, которые для меня лично являются очень важными я буду выносить в отдельные разделы. Как этот, например.

;;;; C-x C-g - перейти к линии
(global-set-key [?\C-x ?\C-g] 'goto-line)

Прячем панели

Со временем понял, что тулбар только место занимает, а пользы от него никакой. Да и некрасивый он какой-то (давно это было, и в Федоре еще, может с современным GTK и набором иконок дела получше обстоят).

;;;; убираем панель с кнопками
(scroll-bar-mode -1)
(tool-bar-mode -1)
; (menu-bar-mode -1)

Табуляция в 4 пробела

И заодно использование пробелов вместо табов. Для питониста это довольно важно.

;;;; Табуляция по-умолчанию - 4 пробела
(setq tab-width 4)

;;;; Пробелы вместо табов
(setq c-basic-indent 4)
(setq tab-width 4)
(setq indent-tabs-mode nil)
(setq-default indent-tabs-mode nil)

Автокомплит

Как ни странно, самым лучшим автокомплитом для меня является сочетание клавиш M-/. Логика его работы проста: ищется слово с похожим префиксом назад по файлу, а также по другим открытым файлам. Если найдено – оно дополняется. Прелесть этого подхода в том, что вы получаете универсальный автокомплит, независимый от языка или чего-либо еще.

Rope (такая утилита, делающая из емакса питон-иде) я отключил (пока что, хотя бы) именно потому, что он переписывает эту комбинацию на свой, “умный” автокомплит (как во всех модных ИДЕ). Ничего удобнее старого доброго M-/ для меня нету.

Причина еще в том, что либо эта функция уже встречалась и использовалась (и автокомплит сработает), либо буфер с её исходником открыт (потому что убогое окошечко с документацией функции и списков из сотни членов класса мне как-то не прижились).

Todo

дописать

ack и поиск по всему проекту

Поиск по проекту у меня бывает двух видов: поиск регулярного выражения и поиск полной строки. Как это ни парадоксально – для второго я просто не нашел инструмента.

Сначала о поиске регулярного выражения. Стандартная функция find-grep слишком тормозна и не пропускает всякие .svn и .hg, потому плохо работает. А есть замечательный пакет ack (sudo apt-get install ack=grep, ну и ack.el), который ищет только по нужным файлам и делает это довольно быстро. Вот, правда, мой ack.el (видимо старой версии) мне больше нравится, чем текущий, потому продублирую его здесь:

;;; ack.el --- Use ack where you might usually use grep.

;; Copyright (C) 2008 Philip Jackson

;; Author: Philip Jackson <phil@shellarchive.co.uk>
;; Version: 0.3

;; This file is not currently part of GNU Emacs.

;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2, or (at
;; your option) any later version.

;; This program 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.

;; You should have received a copy of the GNU General Public License
;; along with this program ; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; ack.el provides a simple compilation mode for the perl grep-a-like
;; ack (http://petdance.com/ack/).

;; If `ack-guess-type' is non-nil and `ack-mode-type-map' has a
;; reasonable value then ack.el will try and guess what you would like
;; in the --type argument for ack.

;; To install/use put ack.el in your load-path and (require 'ack) in
;; your initialisation file. You can then M-x ack and you're off.

(require 'compile)

(defvar ack-guess-type t
  "Setting this value to `t' will have `ack' do its best to fill
in the --type argument to the ack command")

(defvar ack-command "ack-grep --nocolor --nogroup -a "
  "The command to be run by the ack function.")

(defvar ack-mode-type-map
  '(((c++-mode) . "cpp")
    ((c-mode) . "cc")
    ((css-mode) . "css")
    ((emacs-lisp-mode) . "elisp")
    ((fortran-mode) . "fortran")
    ((html-mode) . "html")
    ((xml-mode nxml-mode) . "xml")
    ((java-mode) . "java")
    ((lisp-mode) . "lisp")
    ((perl-mode cperl-mode yaml-mode) . "perl"))
  "alist describing how to fill in the '--type=' argument to ack")

(defun ack-find-type-for-mode ()
  (catch 'found
    (dolist (mode-type ack-mode-type-map)
      (when (member major-mode (car mode-type))
        (throw 'found (cdr mode-type))))))

(defun ack-build-command ()
  (let ((type (ack-find-type-for-mode)))
    (concat ack-command
            (when (and ack-guess-type type)
              (concat "--type=" type)) " -- ")))

(define-compilation-mode ack-mode "Ack"
  "Ack compilation mode."
  nil)

;;;###autoload
(defun ack (command-args)
  (interactive
   (list (read-from-minibuffer "Run ack (like this): "
                               (ack-build-command)
                               nil
                               nil
                               'ack-history)))
   (compilation-start command-args 'ack-mode))

(provide 'ack)

Вам необходимо просто открыть директорию, по которой будете искать (через C-x C-f), а затем набрать M-x ack и набрать регулярное выражение.

Для поиска полной версии строки написал тупейший скрипт на питоне:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
import re

def ok_path_to_search(path):
    return (not path.startswith('.'))

def ok_file_to_search(file_path):
    return ((file_path.endswith('.py') or
             file_path.endswith('.mako') or
             file_path.endswith('.css') or
             file_path.endswith('.js')) and
            not file_path.endswith('.mako.py'))

def search_files(path='.'):
    import os

    for item in os.listdir(path):
        full_item_path = os.path.join(path, item)
        if os.path.isdir(full_item_path) and ok_path_to_search(item):
            for result in search_files(path=full_item_path):
                yield result
        elif ok_file_to_search(item):
            yield full_item_path

class SearchResult(object):
    def __init__(self, line, str_):
        self.line = line
        self.str = str_

def search_in_file(file_, term):
    import codecs

    with codecs.open(file_, 'r', 'utf-8', errors='ignore') as f:
        for i, line in enumerate(f):
            line_no = i + 1
            if term in line:
                yield SearchResult(line=line_no, str_=line)

def output_result(file_, res):
    print u"%s:%s:%s" % (file_, res.line, res.str.rstrip(u'\n'))

def main():
    term = unicode(sys.argv[1], 'utf-8')
    for file_ in search_files():
        for res in search_in_file(file_, term):
            output_result(file_, res)

if __name__ == '__main__':
    main()

и подключил его как-то вот так:

(defun find (command-args)
  (interactive
   (list (read-from-minibuffer "Provide a string at the end: "
                               "python ~/Dropbox/playground/python/search_string.py "
                               nil
                               nil)))
  (compilation-start command-args 'ack-mode))

После этого набираю M-x find и ввожу в кавычках полную фразу, которую необходимо найти. Работает очень даже быстро.

Todo

дописать

python-mode

Todo

дописать

Навигация между буферами

Вообще надо честно признаться, что надо придумать себе сочетание без стрелочек для этого. В основном я переключаюсь при помощи M-o (это значит “переключиться в следующий буфер”), но иногда удобно именно между верхними двумя, к примеру, туда-сюда переключаться.

;;;; навигация между окнами при помощи M-`Arrow keys`
(windmove-default-keybindings 'meta)

Ну и ресайз окон. Им я пользуюсь редко, потому пусть на стрелочках остаётся.

;;;; Делаем чтоб Shift-M-`Arrow keys` ресайзило окна
(defun win-resize-top-or-bot ()
"Figure out if the current window is on top, bottom or in the
middle"
(let* ((win-edges (window-edges))
(this-window-y-min (nth 1 win-edges))
(this-window-y-max (nth 3 win-edges))
(fr-height (frame-height)))
(cond
((eq 0 this-window-y-min) "top")
((eq (- fr-height 1) this-window-y-max) "bot")
(t "mid"))))

(defun win-resize-left-or-right ()
"Figure out if the current window is to the left, right or in the
middle"
(let* ((win-edges (window-edges))
(this-window-x-min (nth 0 win-edges))
(this-window-x-max (nth 2 win-edges))
(fr-width (frame-width)))
(cond
((eq 0 this-window-x-min) "left")
((eq (+ fr-width 4) this-window-x-max) "right")
(t "mid"))))

(defun win-resize-enlarge-horiz ()
(interactive)
(cond
((equal "top" (win-resize-top-or-bot)) (enlarge-window -1))
((equal "bot" (win-resize-top-or-bot)) (enlarge-window 1))
((equal "mid" (win-resize-top-or-bot)) (enlarge-window -1))
(t (message "nil"))))

(defun win-resize-minimize-horiz ()
(interactive)
(cond
((equal "top" (win-resize-top-or-bot)) (enlarge-window 1))
((equal "bot" (win-resize-top-or-bot)) (enlarge-window -1))
((equal "mid" (win-resize-top-or-bot)) (enlarge-window 1))
(t (message "nil"))))

(defun win-resize-enlarge-vert ()
(interactive)
(cond
((equal "left" (win-resize-left-or-right)) (enlarge-window-horizontally -1))
((equal "right" (win-resize-left-or-right)) (enlarge-window-horizontally 1))
((equal "mid" (win-resize-left-or-right)) (enlarge-window-horizontally -1))))

(defun win-resize-minimize-vert ()
(interactive)
(cond
((equal "left" (win-resize-left-or-right)) (enlarge-window-horizontally 1))
((equal "right" (win-resize-left-or-right)) (enlarge-window-horizontally -1))
((equal "mid" (win-resize-left-or-right)) (enlarge-window-horizontally 1))))

(global-set-key [S-M-down] 'win-resize-mi2nimize-vert)
(global-set-key [S-M-up] 'win-resize-enlarge-vert)
(global-set-key [S-M-left] 'win-resize-minimize-horiz)
(global-set-key [S-M-right] 'win-resize-enlarge-horiz)
(global-set-key [S-M-up] 'win-resize-enlarge-horiz)
(global-set-key [S-M-down] 'win-resize-minimize-horiz)
(global-set-key [S-M-left] 'win-resize-enlarge-vert)
(global-set-key [S-M-right] 'win-resize-minimize-vert)

Маленькие хауту

Копирование фрагмента из емакса во внешний мир

Если в емаксе выделить блок и нажать M-w чтоб скопировать его – по умолчанию вы не сможете его вставить во внешнее приложение. Решается это вот так:

;;;; copypaste to X buffer
(setq x-select-enable-clipboard t)

Закрыть все буферы

Иногда надоедает всё и хочется просто всё закрыть (но не перезапускать емакс. Зачем?). Для этого я использую команду close-all-buffers. Вот её реализация:

;;;; Закрывает все активные буферы
(defun close-all-buffers ()
  (interactive)
  (mapc 'kill-buffer (buffer-list)))

Вместо yes или no набирать y и n

;;;; Не надо набирать 'yes' или 'no'. Теперь 'y' либо 'n'
(fset 'yes-or-no-p 'y-or-n-p)

Бекап файлов

Я уже и забыл об этом) Скорее всего эта штука делает бекап всего, что вы редактируете. Потому что бывает так, что не закоммитил, а хочешь вернуть как было. Эклипс по-умолчанию хранит локальную историю, видимо это аналог для емакса.

;;;;Change backup behavior to save in a directory, not in a miscellany
;;;;of files all over the place.
(setq
 backup-by-copying t                                        ; don't clobber symlinks
 backup-directory-alist
 '(("." . "~/.saves"))                                      ; don't litter my fs tree
 delete-old-versions t
 kept-new-versions 6
 kept-old-versions 2
 version-control t)                                         ; use versioned backups

Еще всякое

Думаю, из комментариев станет ясно что вам нравится и что хотите утянуть к себе.

;;;; делаем чтоб при открытии emacs'а не было мусора, а был открыт только один буфер *scratch*
(setq inhibit-splash-screen t)

;;;; Показывать номер колонки
(column-number-mode t)

;;;; Показывать время
(setq display-time-day-and-date t
      display-time-24hr-format t)
(display-time)

;;;; Убеждаемся что .emacs редактируется в elisp-mode'е
(setq auto-mode-alist (cons '("\.emacs" . lisp-mode) auto-mode-alist))

;;;; Прячем ввод пароля
(add-hook 'comint-output-filter-functions
          'comint-watch-for-password-prompt)

;;;; Папка с временными файлами
(setq temporary-file-directory "/tmp/")

;;;;"I always compile my .emacs, saves me about two seconds
;;;;startuptime. But that only helps if the .emacs.elc is newer
;;;;than the .emacs. So compile .emacs if it's not."
(defun autocompile nil
  "compile itself if ~/.emacs"
  (interactive)
  (require 'bytecomp)
  (if (string= (buffer-file-name) (expand-file-name (concat
                                                     default-directory ".emacs")))
      (byte-compile-file (buffer-file-name))))

(add-hook 'after-save-hook 'autocompile)

;;;; Удобство перелкючения между буферами. C-, - предыдущий, C-. - следующий
(global-set-key [?\C-,] 'previous-buffer)
(global-set-key [?\C-.] 'next-buffer)

«  Заголовок окна в емаксе   ::   Contents   ::   Экспортирование из PostgreSQL в MongoDB  »

blog comments powered by Disqus