Emacs cheat sheet

Мой маленький конспект для C-h r

Движение курсора

  • M-g M-g (M-g g)
    перейти к заданой строчке (по умолчанию взять число около курсора)
  • C-u M-g M-g (M-g g)
    перейти к заданой строчке в соседнем окне
  • M-r
    двигает курсор не меняя скрол (vim: H M L)
  • C-u C-SPC
    передвижение по кольцу меток(mark ring)
  • C-x C-SPC
    передвижение по глобальному кольцу меток
  • C-M l
    умный скроллинг (показать заголовок функции)
  • M-x follow-mode
    двух-страничный скролл

Минибуффер

  • C-x ESC ESC
    повторить предыдущую команду

Поиск

  • С-[sr] DEL
    поиск; С-[sr]: след. вхождение; DEL - предыдущее
  • С-M-[sr]
    regexp поиск
  • M-r
    toggle regexp search
  • M-c
    toggle case sensitive
  • M-e
    редактировать текущий шаблон поиска
  • C-w
    добавить слово под курсором к поиску
  • M-s C-e
    добавить к поиску остаток строки
  • C-M-y
    добавить символ под курсором к поиску
  • C-M-w
    удалить символ
  • M-s w
    поиск слов
  • M-x occur / M-s o
    вывести список найденых строк [e - редактировать не месте]
  • M-s w
    Инкрементный поиск по списку слов (игнорирует разделяющую пунктуацию)
  • M-x multi-occur-in-matching-buffers
    occur по буфферам подходящем по regexp
  • M-x how-many
    печатает сколько найдено выражений по regexp'у
  • M-x flush-lines
    удаляет строки по регулярке
  • M-x keep-lines
    удаляет все строки кроме регулярки

Замена

  • M-%
    замена
  • C-M-%
    regexp замена
  • M-x replace-regexp RET pattern RET repl\?ace
    замена по регэкспу с запросом ввода вместо \?

Универсальное

  • C-x z [z +]
    повторить предыдущее действие
  • M-x hi-lock-mode
    режим кастомной подсветки:
  • C-x w h
    Подсветить регулярку
  • C-x w r
    Разподсветить регулярку

Minor modes

  • Mx whitespace-mode
    отображение пробельных символов

Редактирование

  • C-o
    вставить пустую строку после курсора
  • C-x C-o
    удалить пустые строки, оствляя только одну
  • C-q
    вставить непечатный символ или символ по восьмеричному коду
  • C-x 8
    вставить символ юникода по имени или по коду
  • C-M-\
    indent region
  • M-$
    проверить орфографию
  • M-\
    удалить все пробелы около точки
  • M-SPC
    удалить все пробелы кроме одного около точки
  • С-S-BACKSPACE
    удалить всю строку
  • M-z CHAR
    удалить до символа
  • C-M-w + kill command CHAR
    добавить к предыдущему скопированному объекту
  • C-x RET + x
    задать кодировку для X clipboard
  • M-x check-parens
    найти несбалансированные скобки
  • C-t
    обменять местами символы
  • M-t
    обменять местами слова
  • С-M-t
    обменять местами выражения
  • С-x C-t
    обменять местами строки
  • M-- M-l
    предыдущее слово в нижний регистр
  • M-- M-u
    предыдущее слово в верний регистр
  • M-- M-c
    предыдущее слово сделать с большой буквы

Регистры

  • C-x r SPC
    point-to-register
  • C-x w SPC
    window-configuration-to-register
  • C-x f SPC
    frame-configuration-to-register
  • C-x r h
    jump-to-register (alsi restore frames configuration)
  • C-x s SPC
    copy-to-register
  • C-x i SPC
    insert-register

Информация

  • M-=
    показывает количество строк и символов в регионе
  • C-x =
    показывает информацию по символу под курсором
  • M-@ (S-M-2)
    выделить слово не двигая курсор
  • С-M-@ (C-M-SPC)
    выделить sexp не двигая курсор
  • M-h
    курсор в начала параграфа и выделить его
  • C-M-h
    курсор в начала defun и выделить ее
  • C-x h
    выделить весь буфер

Управление буферами

  • C-x k
    Убить буфер
  • C-x 4 C-o
    Переключить буфер в соседнем окне, оставив фокус на текущем
  • M-x ibuffer
    навороченная переключалка
  • M-x buf-move-{up,down,left,right}
    передвинуть окно (buffer-move.el)
  • M-x winner-mode
    История окон C-c left/right undo/redo

Программирование

  • M-x imenu
    переход к определению символа
  • M-x whitespace-mode
    отображает табы и пробелы
  • M-;
    comment-dwim: do what i mean

Справка

  • C-h w COMMAND
    показать биндинги для команды

Файлы

  • C-x RET r
    переоткрыть файл у другой кодировке
  • C-x С-v
    Убить текущий буффер и открыть вместо него новый файл (полезно если случайно открыли не тот файл)
  • C-x 4 f
    Открыть файл во втором окне, создав его если нужно
  • M-x auto-revert-{tail}-mode
    Автоматически обновлять файл с диска при изменениях
  • M-x file-cache-add-directory-using-find
    Добавить директорию в кеш файлов. Автодополнение по C-Tab при открытии.

Настройки

  • M-x load-file
    загрузить и выполнить lisp-файл

Хозяйке на заметку: ack-grep

Как всегда случайно узнал об еще одной утилите — ack-grep. Как описывает ее aptitude:

«Программа наподобии grep для работы с большими деревами исходников»

*("деревами"?!)*Из коробки умеет подсвечивать и группировать найденные строки по файлам.

Состояние клавиш

Сегодня мы научимся узнавать нажата ли клавиша без использования событий. Это возможно благодаря "состоянию клавиш" (keystates). Иногда просто проверить зажата или отпущена клавиша гораздо проще, чем следить за событиями. Этот туториал научит вас проверять нажата ли клавиша, вместо слежения за событиями клавиатуры.
    //Пока пользователь не хочет закрыть приложение
    while( quit == false )
    {
        //Пока есть события на обработку
        while( SDL_PollEvent( &event ) )
        {
            //Если пользователь закрыл окно
            if( event.type == SDL_QUIT )
            {
                //Завершить программу
                quit = true;
            }    
        }

Как вы можете заметить, несмотря на тот факт, что мы показываем сообщения в зависимости от нажатых клавиш, мы не проверяем на события клавиатуры.

        //Получить состояние клавиш
        Uint8 *keystates = SDL_GetKeyState( NULL );

Вместо этого мы используем SDL_GetKeyState(). SDL_GetKeyState() дает нам массив с состоянием клавиш. Этот массив это список всех клавиш и их состояний: нажаты они или нет. Что-то вроде этого: Теперь мы можем сказать какая клавиша нажата. Просто для информации: аргумент который мы передаем в SDL_GetKeyState() получает число доступных клавиш. А т.к. нас это не волнует, мы просто передаем NULL.

        //Если нажата стрелка вверх
        if( keystates[ SDLK_UP ] )
        {
            apply_surface( ( SCREEN_WIDTH - up->w ) / 2, ( SCREEN_HEIGHT / 2 - up->h ) / 2, up, screen );
        }

        //Если нажата стрелка вниз
        if( keystates[ SDLK_DOWN ] )
        {
            apply_surface( ( SCREEN_WIDTH - down->w ) / 2, ( SCREEN_HEIGHT / 2 - down->h ) / 2 + ( SCREEN_HEIGHT / 2 ), down, screen );
        }

        //Если нажата стрелка влево
        if( keystates[ SDLK_LEFT ] )
        {
            apply_surface( ( SCREEN_WIDTH / 2 - left->w ) / 2, ( SCREEN_HEIGHT - left->h ) / 2, left, screen );
        }

        //Если нажата стрелка вправо
        if( keystates[ SDLK_RIGHT ] )
        {
            apply_surface( ( SCREEN_WIDTH / 2 - right->w ) / 2 + ( SCREEN_WIDTH / 2 ), ( SCREEN_HEIGHT - right->h ) / 2, right, screen );
        }
		
        //Обновить экран
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;    
        }

Все просто: если нажата стрелка вверх, показать сообщение "вверх" (up), если нажата стрелка вниз, показать сообщение "вниз" (down) и т.д. Если бы это программа была написана при помощи событий, код был бы на прилично длиннее. SDL_GetKeyState() и другие функции состояний, например SDL_GetModState(), SDL_GetMouseState(), SDL_JoystickGetAxis() и прочие, могут быть невероятно полезны. Узнайте о них больше в документации к SDL.

Скачать исходники

События мыши

Пришло время научится обрабатывать события от мышки. В этом простом туториале мы будем учится обрабатывать различные события мыши, с целью сделать простую кнопку.
//Кнопка
class Button {
private:
    //Атрибуты кнопки
    SDL_Rect box;
    //Часть спрайт листа кнопки, которая будет отображаться
    SDL_Rect* clip;
public:
    //Инициализация переменных
    Button( int x, int y, int w, int h );
    //Обработка событий и выбор спрайта для отображения
    void handle_events();
    //Вывод кнопки на экран
    void show();
};

Это наш класс для кнопки, с которым мы будем взаимодействовать. В нем есть прямоугольник определяющий позицию и размеры кнопки. Так же у нас есть указатель на спрайт из спрайт листа, которым пользуется кнопка. Затем у нас есть конструктор, устанавливающий атрибуты кнопки в соответствие с переданными аргументами. Далее следует функция handle_events(), которая обрабатывает движение и другие события мыши. И наконец функция show() отображающая кнопку на экран.

void set_clips()
{
    //нарезаем спрайты
    clips[ CLIP_MOUSEOVER ].x = 0;
    clips[ CLIP_MOUSEOVER ].y = 0;
    clips[ CLIP_MOUSEOVER ].w = 320;
    clips[ CLIP_MOUSEOVER ].h = 240;

    clips[ CLIP_MOUSEOUT ].x = 320;
    clips[ CLIP_MOUSEOUT ].y = 0;
    clips[ CLIP_MOUSEOUT ].w = 320;
    clips[ CLIP_MOUSEOUT ].h = 240;

    clips[ CLIP_MOUSEDOWN ].x = 0;
    clips[ CLIP_MOUSEDOWN ].y = 240;
    clips[ CLIP_MOUSEDOWN ].w = 320;
    clips[ CLIP_MOUSEDOWN ].h = 240;

    clips[ CLIP_MOUSEUP ].x = 320;
    clips[ CLIP_MOUSEUP ].y = 240;
    clips[ CLIP_MOUSEUP ].w = 320;
    clips[ CLIP_MOUSEUP ].h = 240;    
}

Это наша функция, вырезающая изображения из листа спрайтов: Как вы можете видеть, у нас есть спрайт для различных событий мыши. И у нас есть массив из четырех SDL_Rect's который выкраивает спрайты для каждого состояния кнопки. Каждый спрайт кнопки имеет соответствующую константу.

Button::Button( int x, int y, int w, int h )
{
    //Установить атрибуты
    box.x = x;
    box.y = y;
    box.w = w;
    box.h = h;

    //Спрайт по умолчанию
    clip = &clips[ CLIP_MOUSEOUT ];
}

Конструктор класса кнопки довольно прост. Он устанавляет смещения кнопки по x и y, а так же ширину и высоту. Так же он устанавливает спрайт по умолчанию.

void Button::handle_events()
{
    //Смещения мыши
    int x = 0, y = 0;

    //Если мышь сдвинулась
    if( event.type == SDL_MOUSEMOTION )
    {
        //Получить смещения
        x = event.motion.x;
        y = event.motion.y;

        //Если мышь над кнопкой
        if( ( x > box.x ) && ( x < box.x + box.w ) &&
                ( y > box.y ) && ( y < box.y + box.h ) )
        {
            //Установить соответсвующий спрайт
            clip = &clips[ CLIP_MOUSEOVER ];    
        }
        //Если нет
        else
        {
            //Ставим спрайт
            clip = &clips[ CLIP_MOUSEOUT ];
        }    
    }

В обработчике событий, перво-наперво мы проверяем двигалась ли мышь. Когда мышь движется, происходит событие SDL_MOUSEMOTION Если мышь двинулась, мы получаем ее смещения из структуры события, затем проверяем находится ли она над кнопкой. Если она над ней, мы устанавливаем спрайт Mouse over, или спрайт Mouse out в противном случае.

    //Если была нажата кнопка мыши
    if( event.type == SDL_MOUSEBUTTONDOWN )
    {
        //Если нажили левую
        if( event.button.button == SDL_BUTTON_LEFT )
        {
            //Получить смещения
            x = event.button.x;
            y = event.button.y;

            //Если мышь над кнопкой
            if( ( x > box.x ) && ( x < box.x + box.w ) &&
                    ( y > box.y ) && ( y < box.y + box.h ) )
            {
                //Установить спрайт
                clip =&clips[ CLIP_MOUSEDOWN ];
            }
        }
    }

Затем проверяем было ли нажатие кнопок мыши. При нажатии происходит событие SDL_MOUSEBUTTONDOWN. Мы хотим, чтобы кнопка реагировала только на левую кнопку мыши, так что мы проверяем была ли нажата именно левая кнопка мыши. Далее проверяем было ли нажатие над нашей кнопкой. Если это так, то устанавливаем для кнопки спрайт Mouse down

    //Если кнопку мыши отпустили
    if( event.type == SDL_MOUSEBUTTONUP )
    {
        //Если отпустили левую кнопку
        if( event.button.button == SDL_BUTTON_LEFT )
        {
            //получить смещения
            x = event.button.x;
            y = event.button.y;

            //Если мышь над кнопкой
            if( ( x > box.x ) && ( x < box.x + box.w ) &&
                    ( y > box.y ) && ( y < box.y + box.h ) )
            {
                //Установить спрайт
                clip = &clips[ CLIP_MOUSEUP ];
            }
        }
    }
}

Затем мы проверяем была ли кнопка мыши отпущена над кнопкой с событием SDL_MOUSEBUTTONUP В этой программе мы получаем смещения мыши из структуры события. Было бы более целесообразно получать смещения мыши при помощи SDL_GetMouseState(), но… я слишком ленив, чтобы возвращаться назад и переписывать код.

void Button::show()
{
    //Показать кнопку
    apply_surface( box.x, box.y, buttonSheet, screen, clip );
}

Далее в функции show мы отображаем спрайт кнопки на экране.

    //Нарезать спрайт лист
    set_clips();
    //Сделать кнопку
    Button myButton( 170, 120, 320, 240 );

В начале функции main() после инициализации и загрузки всего что нужно, мы нарезаем спрайт лист и настраиваем нашу кнопку.

    //Пока пользователь не захотел выйти
    while( quit == false )
    {
        //Если есть события для обработки
        if( SDL_PollEvent( &event ) )
        {
            //Обработать события мыши
            myButton.handle_events();

            //Если пользователь пытается закрыть приложение
            if( event.type == SDL_QUIT )
            {
                //Завершить программу
                quit = true;
            }    
        }

        //Залить экран белым
        SDL_FillRect( screen, &screen->clip_rect,
                         SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ) );

        //Показать кнопку
        myButton.show();

        //Обновить экран
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;    
        }
    }

Здесь мы видим наш класс кнопки в действии внутри главного цикла. В начале мы обрабатываем события. Как вы можете видеть мы используем обработчик событий кнопки, а так же проверяем не хочет ли пользователь завершить приложение. Обычно для обработки событий используется цикл while, но в этом (и в предыдущих) мы используем if. Из-за этого обрабатывается одно событие за кадр — таким образом легче видеть отдельные события. В большинстве настоящих приложений используется while, потому что обычно вы хотите обработать все события в очереди в каждом кадре. После обработки события, мы очищаем экран, заливая его белым. Затем мы отображаем кнопку и обновляем экран. И далее главный цикл повторяется, таким образом мы можем отрисовать следующий кадр, пока пользователь не захочет выйти. Если у вас быстрый компьютер, вы скорее всего не увидите спрайт CLIP_MOUSEUP. Это происходит потому, что приложении работает так быстро, что он отображается только долю секунды. К счастью, далее будет группа туториалов, показывающих как рассчитывать время и регулировать скорость кадров. Если вы замедлите выполнение программы до 20 кадров в секунду у вы хотя бы сможете заметить его.

Скачать исходники

Нажатия клавиш

Этот урок рассказывает о том, как обнаруживать нажатия клавиш. Мы будем писать простую программу, показывающую какая из клавиш\-стрелок была нажата. Мы уже делали простую обработку событий (`SDL_QUIT`). Сегодня мы разберемся с тем, как определять что была нажата клавиша, и что это была за клавиша.
    //Сгенерировать поверхности с сообщениями
    upMessage = TTF_RenderText_Solid( font, "Up was pressed.", textColor );
    downMessage = TTF_RenderText_Solid( font, "Down was pressed.", textColor );
    leftMessage = TTF_RenderText_Solid( font, "Left was pressed", textColor );
    rightMessage = TTF_RenderText_Solid( font, "Right was pressed", textColor );

После того, как все инициализировано и загружено, мы генерируем 4 поверхности с сообщениями. Мне вероятно следовало бы проверять на ошибки при рендеринге текста, но ... хм, так меньше печатать.

    //Если есть событие для обработки
    if( SDL_PollEvent( &event ) ) {
        //Если была нажата клавиша
        if( event.type == SDL_KEYDOWN ) {

Теперь, когда мы хотим проверить была ли нажата клавиша, мы проверяем равен ли тип события SDL_KEYDOWN.

            //Выбрать правильное сообщение
            switch( event.key.keysym.sym ) {
                case SDLK_UP: message = upMessage; break;
                case SDLK_DOWN: message = downMessage; break;
                case SDLK_LEFT: message = leftMessage; break;
                case SDLK_RIGHT: message = rightMessage; break;
            }
        }
        //Если пользователь хочет выйти
        else if( event.type == SDL_QUIT ) {
            //Выходим из программы
            quit = true;
        }
    }

Теперь, если была нажата клавиша, мы должны проверить что это была за клавиша.SDL_PollEvent() кладет данные типа SDL_KEYDOWN в структуру события как SDL_KeyboardEvent по имени key: и внутри key находится структура keysym: а внутри keysym SDL_Key под названием sym, который хранит информацию о том какая кнопка была нажата. Если была нажата стрелка вверх, sym будет равен SDLK_UP и мы выберем сообщение "вверх", если sym будет равен SDLK_DOWN мы выберем сообщение "вниз" и т.д. Посмотреть все определения SDL_Key вы можете в документации по SDL. Так же мы проверяем не хочет ли пользователь выйти и соответствующим образом обрабатываем это событие. Замечание: Некоторые IDE, типа Code::Blocks, включают флаг -Wall по умолчанию. Из-за этого компилятор может жаловаться на то что у вас нет выражений case для всех возможных значений. Чтобы компилятор перестал жаловаться просто добавьте в конец блока switch:

default : ;

    //Если есть сообщение для отображения
    if( message != NULL ) {
        //Скопировать сообщение на экран
        apply_surface( 0, 0, background, screen );
        apply_surface(
            ( SCREEN_WIDTH - message->w ) / 2,
            ( SCREEN_HEIGHT - message->h ) / 2,
            message,
            screen
        );
        //Обнулить указатель на поверхность сообщения
        message = NULL;
    }
    //Обновить экран
    if( SDL_Flip( screen ) == -1 ) {
        return 1;
    }

Если поверхность сообщения никуда не указывает, ее значение будет NULL и ничего не будет скопировано. В обратном случае мы копируем фон и затем помещаем сообщение по центру экрана. Способ центрирования заключается в вычитании ширины/высоты копируемой поверхности из ширины/высоты поверхности на которую вы копируете. А так как поверхность должна быть отцентрирована, отступ с обеих сторон должен быть одинаковым, поэтому мы делим оставшееся расстояние пополам. После этого мы сбрасываем сообщение в NULL и обновляем экран.

Скачать исходники и материалы