vimgolf 0.4.5 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +2 -10
- data/lib/vimgolf.rb +3 -0
- data/lib/vimgolf/challenge.rb +70 -45
- data/lib/vimgolf/cli.rb +96 -31
- data/lib/vimgolf/keylog.rb +253 -207
- data/lib/vimgolf/ui.rb +13 -1
- data/lib/vimgolf/version.rb +1 -1
- data/lib/vimgolf/vimgolf.vimrc +28 -0
- metadata +110 -91
- data/.gitignore +0 -4
- data/.gitmodules +0 -3
- data/.rspec +0 -0
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -30
- data/Rakefile +0 -10
- data/emacs/README.md +0 -69
- data/emacs/ROADMAP.md +0 -69
- data/emacs/features/emacs.feature +0 -24
- data/emacs/features/step-definitions/emacs-steps.el +0 -53
- data/emacs/features/support/env.el +0 -37
- data/emacs/todo.org +0 -45
- data/emacs/vimgolf.el +0 -484
- data/spec/challenge_spec.rb +0 -31
- data/spec/cli_spec.rb +0 -25
- data/spec/fixtures/4d19832d8ae121365c00000b.log +0 -1
- data/spec/fixtures/4d1a1c36567bac34a9000002.log +0 -1
- data/spec/fixtures/4d1a1c69567bac34a9000004.log +0 -1
- data/spec/fixtures/4d1a21e88ae121365c00000e.log +0 -1
- data/spec/fixtures/4d1a34ccfa85f32065000004.log +0 -1
- data/spec/helper.rb +0 -25
- data/spec/keylog_spec.rb +0 -16
- data/vimgolf.gemspec +0 -42
data/emacs/ROADMAP.md
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
# VimGolf Minor Mode Roadmap
|
2
|
-
|
3
|
-
## Features
|
4
|
-
|
5
|
-
1. Completing read of challenges by title rather than by challenge id
|
6
|
-
|
7
|
-
2. `M-x vimgolf-browse`: Dired/Ibuffer/Magit-like interface to VimGolf challenges.
|
8
|
-
|
9
|
-
Bindings:
|
10
|
-
|
11
|
-
- Bindings should mimic Dired/Ibuffer wherever possible. Magit is listed primarily because I want TAB to open up the long description of the challenge.
|
12
|
-
|
13
|
-
At least:
|
14
|
-
|
15
|
-
- n/p
|
16
|
-
- ENTER/o: launch `vimgolf` with the correct arg.
|
17
|
-
|
18
|
-
Interface Mockup:
|
19
|
-
|
20
|
-
VimGolf in Emacs! Compete on vimgolf with the One True Editor.
|
21
|
-
|
22
|
-
Sort entries based on date - Sort some entries in a Ledger-file based on date.
|
23
|
-
PHP Array Syntax -> MailChimp Merge Syntax - I recently needed to send an e-m...
|
24
|
-
Refactor to Helpers
|
25
|
-
This Rails partial is almost all template escapes. Put it into a helper,
|
26
|
-
and refactor each case to methods so we can build out the controls for
|
27
|
-
each. (I've converted to tabs - fighting with Vimgolf's default config
|
28
|
-
shouldn't be part of the challenge.)
|
29
|
-
|
30
|
-
Alphabetize the directory - Put the contacts and their information in alphabe...
|
31
|
-
PHP <--> Java class conversion Part 2 - Same class but reverse!
|
32
|
-
PHP <--> Java class conversion Part 1 - Convert this tiny php class to adequa...
|
33
|
-
Multiplication table. - Create a multiplication table.
|
34
|
-
Complete the hex array data (Part II) - Do not use external tools(e.g. tac, s...
|
35
|
-
Interweave two blocks of text - Suppose you've got data on a list of things f...
|
36
|
-
.
|
37
|
-
.
|
38
|
-
.
|
39
|
-
|
40
|
-
--------------------------------------------------------------------------------
|
41
|
-
|
42
|
-
Commentary:
|
43
|
-
|
44
|
-
- Tab has been pressed on the Refactor to Helpers line and thus it's been expanded.
|
45
|
-
|
46
|
-
- The challenges `formatted text to markdown` and `Line Zipper` have both been completed and thus are hidden. Could provide a customization setting that turns this off completely, as well as an `M-x vimgolf-show-all` function to toggle the hiding.
|
47
|
-
|
48
|
-
- Fill column has been set to 80
|
49
|
-
|
50
|
-
- It would be fun if a local cache of the vimgolf data could be kept together so that you could record solutions or at least play offline.
|
51
|
-
|
52
|
-
3. Real submission to vimgolf.
|
53
|
-
|
54
|
-
This could look like:
|
55
|
-
|
56
|
-
Pop-open buffer
|
57
|
-
|
58
|
-
You solved the formatted text to markdown challenge in 25 keystrokes! The best entry for this challenge was 23.
|
59
|
-
|
60
|
-
M-x qrr ;; query-replace-regexp
|
61
|
-
SPC*2 ;; self-insert-command
|
62
|
-
dummy ;; self-insert-command * 5
|
63
|
-
.
|
64
|
-
.
|
65
|
-
.
|
66
|
-
|
67
|
-
Mini-buffer
|
68
|
-
|
69
|
-
Submit to your solution to vimgolf? <y-or-n-predicate>
|
@@ -1,24 +0,0 @@
|
|
1
|
-
Feature: VimGolf Browser
|
2
|
-
In order to browse and select VimGolf entries
|
3
|
-
As a user
|
4
|
-
I want to use the VimGolf browser
|
5
|
-
|
6
|
-
Scenario: Press TAB on entry to view description
|
7
|
-
Given I open the vimgolf browser
|
8
|
-
Then I should not see "Continuing from the last challenge"
|
9
|
-
When I press "TAB"
|
10
|
-
Then I should see "Continuing from the last challenge"
|
11
|
-
When I press "TAB"
|
12
|
-
Then I should not see "Continuing from the last challenge"
|
13
|
-
|
14
|
-
Scenario: Move through the browse list
|
15
|
-
Given I open the vimgolf browser
|
16
|
-
Then the cursor should be before "Compl"
|
17
|
-
When I press "n"
|
18
|
-
Then the cursor should be before "Make "
|
19
|
-
When I press "n"
|
20
|
-
Then the cursor should be before "Conve"
|
21
|
-
When I press "p"
|
22
|
-
Then the cursor should be before "Make "
|
23
|
-
When I press "p"
|
24
|
-
Then the cursor should be before "Compl"
|
@@ -1,53 +0,0 @@
|
|
1
|
-
;; This file contains your project specific step definitions. All
|
2
|
-
;; files in this directory whose names end with "-steps.el" will be
|
3
|
-
;; loaded automatically by Ecukes.
|
4
|
-
|
5
|
-
(Given "^I open the vimgolf browser$"
|
6
|
-
(lambda ()
|
7
|
-
(setq *vimgolf-browse-list*
|
8
|
-
'(("50128129201f450002000027"
|
9
|
-
"Complete the circuit grid!"
|
10
|
-
"Continuing from the last challenge, add additional rows to the grid. Change each of the names from 'A1'...'A10' to 'B1'...'B10', 'C1'...'C10', etc, and for each new row add 0.7 to the X values in the (X Y) at the end of each line. ")
|
11
|
-
("50127eba201f450002000024"
|
12
|
-
"Make the circuit grid!"
|
13
|
-
"Copy this command for a circuit layout program to create 10 total smd commands. Increment the number in quotes to name each pad, and add 0.7 to each of the (X Y) coordinates at the end of each line.")
|
14
|
-
("500855e60599d90002000073"
|
15
|
-
"Convert pandoc unordered list to a numbered list"
|
16
|
-
"I know it's possible to use #. in pandoc to auto-generate numbered lists, but then it's not easy to tell how many items there are when reading it in Markdown. How fast can you make the switch?")
|
17
|
-
("4fe62f8a8b2f800001000043"
|
18
|
-
"Cleanining up 80 column concatenated text"
|
19
|
-
"1. Put the whole query on one line, remove the concatenation operators
|
20
|
-
("4d1b4ac3c58eaa2a8a0005c2"
|
21
|
-
"Ruby 1.9 compat"
|
22
|
-
"Remember when Ruby supported `when <expr> :`? Well, it doesn't in 1.9, so let's make sure we use `then`, without ruining our lovely new hash syntax!")
|
23
|
-
))
|
24
|
-
(vimgolf-browse)))
|
25
|
-
|
26
|
-
(When "^I show the description$"
|
27
|
-
(lambda ()
|
28
|
-
(vimgolf-show-description)))
|
29
|
-
|
30
|
-
(Given "^I have \"\\(.+\\)\"$"
|
31
|
-
(lambda (something)
|
32
|
-
;; Do something
|
33
|
-
))
|
34
|
-
|
35
|
-
(When "^I have \"\\(.+\\)\"$"
|
36
|
-
(lambda (something)
|
37
|
-
;; Do something
|
38
|
-
))
|
39
|
-
|
40
|
-
(Then "^I should have \"\\(.+\\)\"$"
|
41
|
-
(lambda (something)
|
42
|
-
;; Do something
|
43
|
-
))
|
44
|
-
|
45
|
-
(And "^I have \"\\(.+\\)\"$"
|
46
|
-
(lambda (something)
|
47
|
-
;; Do something
|
48
|
-
))
|
49
|
-
|
50
|
-
(But "^I should not have \"\\(.+\\)\"$"
|
51
|
-
(lambda (something)
|
52
|
-
;; Do something
|
53
|
-
))
|
@@ -1,37 +0,0 @@
|
|
1
|
-
;; This is an example of how you could set up this file. This setup
|
2
|
-
;; requires a directory called util in the project root and that the
|
3
|
-
;; util directory contains the testing tools ert and espuds.
|
4
|
-
|
5
|
-
(let* ((features-directory
|
6
|
-
(file-name-directory
|
7
|
-
(directory-file-name (file-name-directory load-file-name))))
|
8
|
-
(project-directory
|
9
|
-
(file-name-directory
|
10
|
-
(directory-file-name features-directory))))
|
11
|
-
(setq emacs-root-path project-directory)
|
12
|
-
(setq emacs-util-path (expand-file-name "util" emacs-root-path)))
|
13
|
-
|
14
|
-
(add-to-list 'load-path emacs-root-path)
|
15
|
-
(add-to-list 'load-path (expand-file-name "espuds" emacs-util-path))
|
16
|
-
(add-to-list 'load-path (expand-file-name "ert" emacs-util-path))
|
17
|
-
|
18
|
-
(require 'vimgolf)
|
19
|
-
(require 'espuds)
|
20
|
-
(require 'ert)
|
21
|
-
|
22
|
-
|
23
|
-
(Setup
|
24
|
-
;; Before anything has run
|
25
|
-
)
|
26
|
-
|
27
|
-
(Before
|
28
|
-
;; Before each scenario is run
|
29
|
-
)
|
30
|
-
|
31
|
-
(After
|
32
|
-
;; After each scenario is run
|
33
|
-
)
|
34
|
-
|
35
|
-
(Teardown
|
36
|
-
;; After when everything has been run
|
37
|
-
)
|
data/emacs/todo.org
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
* VimGolf TODO
|
2
|
-
|
3
|
-
** Game Excersizes
|
4
|
-
|
5
|
-
** Browser
|
6
|
-
*** DONE Handle/fix character encoding
|
7
|
-
CLOSED: [2012-07-28 Sat 23:07]
|
8
|
-
:LOGBOOK:
|
9
|
-
- State "DONE" from "TODO" [2012-07-28 Sat 23:07] \\
|
10
|
-
Added a utility function to handling <, >, &, and ".
|
11
|
-
:END:
|
12
|
-
Things like < and >, etc.
|
13
|
-
*** DONE Fix line endings
|
14
|
-
CLOSED: [2012-07-28 Sat 22:51]
|
15
|
-
:LOGBOOK:
|
16
|
-
- State "DONE" from "TODO" [2012-07-28 Sat 22:51] \\
|
17
|
-
Added a function to replace ^M with some replacement (default space).
|
18
|
-
Currently only running this function on entry descriptions.
|
19
|
-
:END:
|
20
|
-
Need to convert ^M characters
|
21
|
-
*** DONE Add/fix line wrapping
|
22
|
-
CLOSED: [2012-07-28 Sat 22:04]
|
23
|
-
:LOGBOOK:
|
24
|
-
- State "DONE" from "TODO" [2012-07-28 Sat 22:04]
|
25
|
-
:END:
|
26
|
-
Can't assume that everyone's emacs will be set the same. Should really set a
|
27
|
-
particular fill-column and enforce it.
|
28
|
-
*** DONE Truncate long titles
|
29
|
-
CLOSED: [2012-07-28 Sat 22:21]
|
30
|
-
:LOGBOOK:
|
31
|
-
- State "DONE" from "IN PROGRESS" [2012-07-28 Sat 22:21]
|
32
|
-
- State "IN PROGRESS" from "TODO" [2012-07-28 Sat 22:09]
|
33
|
-
:END:
|
34
|
-
Use ellipses to truncate titles that would normally be longer than the
|
35
|
-
fill-column width.
|
36
|
-
*** DONE When first loading (via url-retrieve), list isn't showing after the call
|
37
|
-
CLOSED: [2012-07-28 Sat 23:11]
|
38
|
-
:LOGBOOK:
|
39
|
-
- State "DONE" from "TODO" [2012-07-28 Sat 23:11] \\
|
40
|
-
The list insertion was happening outside of the async callback. Now it happens
|
41
|
-
during the callback (if url-retrieve is used) and during the browse function
|
42
|
-
itself (if not).
|
43
|
-
:END:
|
44
|
-
I'm not sure if the call back isn't working or what. Manually refreshing
|
45
|
-
will display the list.
|
data/emacs/vimgolf.el
DELETED
@@ -1,484 +0,0 @@
|
|
1
|
-
;;; vimgolf.el --- VimGolf interface for the One True Editor
|
2
|
-
;; Copyright (C) never, by no one
|
3
|
-
|
4
|
-
;;; Author: Tim Visher <tim.visher@gmail.com>
|
5
|
-
;;; Maintainer: Tim Visher <tim.visher@gmail.com>
|
6
|
-
;;; Created: 2011-11-02
|
7
|
-
;;; Version: 0.9.3
|
8
|
-
;;; Keywords: games vimgolf vim
|
9
|
-
|
10
|
-
;; This file is not part of GNU Emacs
|
11
|
-
|
12
|
-
;;; Commentary:
|
13
|
-
|
14
|
-
;; This is a simple package that allows Emacs users to compete on [VimGolf][1]
|
15
|
-
;; using the One True Editor. Competition can be commenced utilizing `M-x
|
16
|
-
;; vimgolf`. When finished with a challenge, `C-c C-v C-c` should finish your
|
17
|
-
;; editing, ensure correctness, and submit your score and keystrokes to
|
18
|
-
;; [VimGolf][1].
|
19
|
-
;;
|
20
|
-
;; On second thought, let's not go to Camelot. It's a silly place.
|
21
|
-
;;
|
22
|
-
;; Patches are accepted at https://github.com/timvisher/vimgolf
|
23
|
-
;;
|
24
|
-
;; [1]: http://vimgolf.com/
|
25
|
-
|
26
|
-
;;; Installation:
|
27
|
-
|
28
|
-
;; Use package.el. You'll need to add Marmalade to your archives:
|
29
|
-
|
30
|
-
;; (require 'package)
|
31
|
-
;; (add-to-list 'package-archives
|
32
|
-
;; '("marmalade" . "http://marmalade-repo.org/packages/"))
|
33
|
-
|
34
|
-
;; If you use a version of Emacs prior to 24 that doesn't include
|
35
|
-
;; package.el, you can get it from http://bit.ly/pkg-el23. If you have
|
36
|
-
;; an older package.el installed from tromey.com, you should upgrade
|
37
|
-
;; in order to support installation from multiple sources.
|
38
|
-
|
39
|
-
;;; License:
|
40
|
-
|
41
|
-
;; [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/)
|
42
|
-
|
43
|
-
;;; Contributors
|
44
|
-
|
45
|
-
;; Tim Visher (@timvisher)
|
46
|
-
;; Steve Purcell (@sanityinc)
|
47
|
-
;; Adam Collard (@acollard)
|
48
|
-
|
49
|
-
;;; Code:
|
50
|
-
|
51
|
-
(defgroup vimgolf nil
|
52
|
-
"Compete on VimGolf with the One True Editor."
|
53
|
-
:prefix "vimgolf-"
|
54
|
-
:group 'applications)
|
55
|
-
|
56
|
-
(defcustom vimgolf-key nil
|
57
|
-
"Your VimGolf API Key. Must be set in order to submit your solution."
|
58
|
-
:type 'string
|
59
|
-
:group 'vimgolf)
|
60
|
-
|
61
|
-
(defcustom vimgolf-mode-hook '((lambda () (whitespace-mode t)))
|
62
|
-
"A list of functions to call upon the initialization of vimgolf-mode."
|
63
|
-
:type 'hook
|
64
|
-
:group 'vimgolf)
|
65
|
-
|
66
|
-
(defvar vimgolf-mode-map
|
67
|
-
(let ((map (make-sparse-keymap)))
|
68
|
-
(define-key map (kbd "C-c C-v C-c") 'vimgolf-submit)
|
69
|
-
(define-key map (kbd "C-c C-v r") 'vimgolf-revert)
|
70
|
-
(define-key map (kbd "C-c C-v d") 'vimgolf-diff)
|
71
|
-
(define-key map (kbd "C-c C-v c") 'vimgolf-continue)
|
72
|
-
(define-key map (kbd "C-c C-v p") 'vimgolf-pause)
|
73
|
-
(define-key map (kbd "C-c C-v q") 'vimgolf-quit)
|
74
|
-
map))
|
75
|
-
|
76
|
-
(define-minor-mode vimgolf-mode
|
77
|
-
"Toggle VimGolf mode.
|
78
|
-
|
79
|
-
With no argument, this command toggles the mode. Non-null prefix
|
80
|
-
argument turns on the mode. Null prefix argument turns off the
|
81
|
-
mode.
|
82
|
-
|
83
|
-
When VimGolf mode is enabled, several key bindings are defined
|
84
|
-
with `C-c C-v` prefixes to help in playing VimGolf.
|
85
|
-
|
86
|
-
\\{vimgolf-mode-map}"
|
87
|
-
;; The initial value.
|
88
|
-
nil
|
89
|
-
;; The indicator for the mode line.
|
90
|
-
" VimGolf"
|
91
|
-
;; The minor mode bindings.
|
92
|
-
:keymap vimgolf-mode-map
|
93
|
-
:group 'vimgolf)
|
94
|
-
|
95
|
-
(defvar vimgolf-challenge nil)
|
96
|
-
(defvar vimgolf-challenge-history nil)
|
97
|
-
|
98
|
-
(defvar vimgolf-prior-window-configuration nil)
|
99
|
-
|
100
|
-
(defvar vimgolf-working-window-configuration nil)
|
101
|
-
|
102
|
-
(defvar vimgolf-work-buffer-name "*vimgolf-work*")
|
103
|
-
(defvar vimgolf-start-buffer-name "*vimgolf-start*")
|
104
|
-
(defvar vimgolf-end-buffer-name "*vimgolf-end*")
|
105
|
-
(defvar vimgolf-keystrokes-buffer-name "*vimgolf-keystrokes*")
|
106
|
-
|
107
|
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
108
|
-
;; Keystroke logging
|
109
|
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
110
|
-
|
111
|
-
(defmacro vimgolf-with-saved-command-environment (&rest body)
|
112
|
-
`(let ((deactivate-mark nil)
|
113
|
-
(this-command this-command)
|
114
|
-
(last-command last-command))
|
115
|
-
,@body))
|
116
|
-
|
117
|
-
(defun vimgolf-capturable-keystroke-p ()
|
118
|
-
(not (or executing-kbd-macro
|
119
|
-
(member this-command
|
120
|
-
'(digit-argument
|
121
|
-
negative-argument
|
122
|
-
universal-argument
|
123
|
-
universal-argument-other-key
|
124
|
-
universal-argument-minus
|
125
|
-
universal-argument-more
|
126
|
-
isearch-other-meta-char))
|
127
|
-
(string-prefix-p "vimgolf-" (symbol-name this-command)))))
|
128
|
-
|
129
|
-
(defun vimgolf-capturable-dangling-keystroke-p ()
|
130
|
-
(member this-command
|
131
|
-
'(calc-dispatch)))
|
132
|
-
|
133
|
-
(defvar vimgolf-keystrokes nil
|
134
|
-
"A list of (keys-vector . command) pairs for the keystrokes entered.
|
135
|
-
|
136
|
-
Each entry is a cons cell containing a key sequence vector
|
137
|
-
suitable for use with `key-description', and a symbol for the
|
138
|
-
command that was executed as a result (which may be nil if an
|
139
|
-
unknown key sequence was entered).")
|
140
|
-
|
141
|
-
(defun vimgolf-maybe-capture-keystroke (pred)
|
142
|
-
"Store the keystrokes for `this-command' if result of calling function `PRED' is not nil."
|
143
|
-
(vimgolf-with-saved-command-environment
|
144
|
-
(when (funcall pred)
|
145
|
-
(setq vimgolf-keystrokes
|
146
|
-
(append vimgolf-keystrokes (list (cons (this-command-keys-vector)
|
147
|
-
this-command)))))))
|
148
|
-
|
149
|
-
(defun vimgolf-capture-keystroke ()
|
150
|
-
(vimgolf-maybe-capture-keystroke 'vimgolf-capturable-keystroke-p))
|
151
|
-
|
152
|
-
(defun vimgolf-capture-dangling-keystroke ()
|
153
|
-
(vimgolf-maybe-capture-keystroke 'vimgolf-capturable-dangling-keystroke-p))
|
154
|
-
|
155
|
-
(defun vimgolf-get-keystrokes-as-string (&optional separator)
|
156
|
-
(unless separator (setq separator " "))
|
157
|
-
(mapconcat 'key-description (mapcar 'car vimgolf-keystrokes) separator))
|
158
|
-
|
159
|
-
(defun vimgolf-refresh-keystroke-log ()
|
160
|
-
"Refresh the contents of the keystrokes log buffer."
|
161
|
-
(let ((deactivate-mark nil))
|
162
|
-
(with-current-buffer (get-buffer-create vimgolf-keystrokes-buffer-name)
|
163
|
-
(vimgolf-mode t)
|
164
|
-
(erase-buffer)
|
165
|
-
(insert (format "Challenge ID: %s\n%s\n\n" vimgolf-challenge (vimgolf-challenge-url vimgolf-challenge))
|
166
|
-
(format "Keystrokes (%d):\n\n" (vimgolf-count-keystrokes))
|
167
|
-
(vimgolf-get-keystrokes-as-string)
|
168
|
-
"\n\nFull command log:\n\n")
|
169
|
-
(when vimgolf-keystrokes
|
170
|
-
(let* ((descrs-and-commands
|
171
|
-
(mapcar (lambda (entry) (cons (key-description (car entry)) (cdr entry))) vimgolf-keystrokes))
|
172
|
-
(maxlen (apply 'max (mapcar 'length (mapcar 'car descrs-and-commands))))
|
173
|
-
(fmt (format "%%-%ds %%s" maxlen)))
|
174
|
-
(dolist (entry descrs-and-commands)
|
175
|
-
(insert (format fmt (car entry) (prin1-to-string (cdr entry) t)) "\n")))))))
|
176
|
-
|
177
|
-
(defun vimgolf-enable-capture (enable)
|
178
|
-
"Enable keystroke logging if `ENABLE' is non-nil otherwise disable it."
|
179
|
-
(let ((f (if enable 'add-hook 'remove-hook)))
|
180
|
-
(funcall f 'pre-command-hook 'vimgolf-capture-keystroke)
|
181
|
-
(funcall f 'post-command-hook 'vimgolf-capture-dangling-keystroke)
|
182
|
-
(funcall f 'post-command-hook 'vimgolf-refresh-keystroke-log)))
|
183
|
-
|
184
|
-
(defun vimgolf-count-keystrokes ()
|
185
|
-
(apply '+ (mapcar 'length (mapcar 'car vimgolf-keystrokes))))
|
186
|
-
|
187
|
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
188
|
-
;; Managing and scoring challenges
|
189
|
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
190
|
-
|
191
|
-
(defun vimgolf-solution-correct-p ()
|
192
|
-
"Return t if the work text is identical to the solution, nil otherwise."
|
193
|
-
(let ((working (with-current-buffer vimgolf-work-buffer-name (buffer-string)))
|
194
|
-
(end (with-current-buffer vimgolf-end-buffer-name (buffer-string))))
|
195
|
-
(string= working end)))
|
196
|
-
|
197
|
-
(defun vimgolf-wrong-solution ()
|
198
|
-
(message "Wrong!")
|
199
|
-
(vimgolf-diff))
|
200
|
-
|
201
|
-
(defun vimgolf-right-solution ()
|
202
|
-
(delete-other-windows)
|
203
|
-
(switch-to-buffer vimgolf-keystrokes-buffer-name)
|
204
|
-
(message "Hurray! You solved %s in %d keystrokes!" vimgolf-challenge (vimgolf-count-keystrokes)))
|
205
|
-
|
206
|
-
(defun vimgolf-submit ()
|
207
|
-
"Stop the challenge and attempt to submit the solution to VimGolf."
|
208
|
-
(interactive)
|
209
|
-
(vimgolf-enable-capture nil)
|
210
|
-
(if (vimgolf-solution-correct-p) (vimgolf-right-solution) (vimgolf-wrong-solution)))
|
211
|
-
|
212
|
-
(defun vimgolf-clear-keystrokes ()
|
213
|
-
(setq vimgolf-keystrokes nil))
|
214
|
-
|
215
|
-
(defun vimgolf-reset-work-buffer ()
|
216
|
-
"Reset the contents of the work buffer, and clear undo/macro history etc."
|
217
|
-
(with-current-buffer (get-buffer-create vimgolf-work-buffer-name)
|
218
|
-
(vimgolf-init-buffer (current-buffer)
|
219
|
-
(with-current-buffer vimgolf-start-buffer-name
|
220
|
-
(buffer-string)))
|
221
|
-
(when defining-kbd-macro
|
222
|
-
(end-kbd-macro))
|
223
|
-
(vimgolf-clear-keystrokes)
|
224
|
-
(setq buffer-undo-list nil)
|
225
|
-
(set-buffer-modified-p nil)))
|
226
|
-
|
227
|
-
(defun vimgolf-revert ()
|
228
|
-
"Revert the work buffer to it's original state and reset keystrokes."
|
229
|
-
(interactive)
|
230
|
-
(vimgolf-reset-work-buffer)
|
231
|
-
(set-window-configuration vimgolf-working-window-configuration)
|
232
|
-
(message "If at first you don't succeed, try, try again."))
|
233
|
-
|
234
|
-
(defun vimgolf-diff ()
|
235
|
-
"Pause the competition and view differences between the buffers."
|
236
|
-
(interactive)
|
237
|
-
(vimgolf-enable-capture nil)
|
238
|
-
(ediff-buffers (get-buffer-create vimgolf-work-buffer-name) (get-buffer-create vimgolf-end-buffer-name))
|
239
|
-
(message "Remember to `C-c C-v c` when you're done."))
|
240
|
-
|
241
|
-
(defun vimgolf-continue ()
|
242
|
-
"Restore work and end buffers and begin recording keystrokes again."
|
243
|
-
(interactive)
|
244
|
-
(vimgolf-enable-capture t)
|
245
|
-
(set-window-configuration vimgolf-working-window-configuration)
|
246
|
-
(message "Golf away!"))
|
247
|
-
|
248
|
-
(defun vimgolf-pause ()
|
249
|
-
"Stop recording keystrokes."
|
250
|
-
(interactive)
|
251
|
-
(vimgolf-enable-capture nil)
|
252
|
-
(message "Come `C-c C-v c` soon."))
|
253
|
-
|
254
|
-
(defun vimgolf-quit ()
|
255
|
-
"Cancel the competition."
|
256
|
-
(interactive)
|
257
|
-
(vimgolf-enable-capture nil)
|
258
|
-
(vimgolf-kill-existing-session)
|
259
|
-
(set-window-configuration vimgolf-prior-window-configuration)
|
260
|
-
(message "I declare you, n00b!"))
|
261
|
-
|
262
|
-
(defvar vimgolf-host "http://vimgolf.com/")
|
263
|
-
|
264
|
-
;; (setq vimgolf-host "http://vimgolf.local:8888/")
|
265
|
-
;; (setq vimgolf-host "http://vimgolf.com/")
|
266
|
-
;; Overall VimGolf Rank ID: 4d2fb20e63b08b08b0000075
|
267
|
-
;; Sort entries based on date ID: 4ea9bc988b36f70001000008
|
268
|
-
;; HTML to Haml ID: 4d3c51f1aabf526ed6000030
|
269
|
-
;; Assignment Allignment: 4d2c9d06eda6262e4e00007a
|
270
|
-
|
271
|
-
(defvar vimgolf-challenge-extension ".yaml")
|
272
|
-
|
273
|
-
(defun vimgolf-challenge-path (challenge-id)
|
274
|
-
(concat "challenges/" challenge-id))
|
275
|
-
|
276
|
-
(defun vimgolf-challenge-url (challenge-id)
|
277
|
-
(concat vimgolf-host (vimgolf-challenge-path challenge-id) vimgolf-challenge-extension))
|
278
|
-
|
279
|
-
(defun vimgolf-init-buffer (buffer text)
|
280
|
-
(with-current-buffer buffer
|
281
|
-
(erase-buffer)
|
282
|
-
(insert text)
|
283
|
-
(goto-char (point-min))
|
284
|
-
(vimgolf-mode t)))
|
285
|
-
|
286
|
-
(defun vimgolf-kill-existing-session ()
|
287
|
-
"Kill any vimgolf-related buffers."
|
288
|
-
(dolist (buf (list vimgolf-start-buffer-name
|
289
|
-
vimgolf-work-buffer-name
|
290
|
-
vimgolf-end-buffer-name
|
291
|
-
vimgolf-keystrokes-buffer-name))
|
292
|
-
(when (get-buffer buf)
|
293
|
-
(kill-buffer buf))))
|
294
|
-
|
295
|
-
(defun vimgolf-read-next-data-chunk ()
|
296
|
-
"Return the next chunk of data as a string, leaving the point at the end of that chunk."
|
297
|
-
(let ((data-start-regexp " data: |\\+\\{0,1\\}\n")
|
298
|
-
(data-end-regexp "\\([ ]\\{4\\}\\|[ ]\\{0\\}\\)\n type: [-a-z]+"))
|
299
|
-
(unless (re-search-forward data-start-regexp nil t)
|
300
|
-
(error "Can't find data in response from vimgolf"))
|
301
|
-
(let ((start (point)))
|
302
|
-
(unless (re-search-forward data-end-regexp nil t)
|
303
|
-
(error "Unclosed data section in response from vimgolf"))
|
304
|
-
(let ((str (buffer-substring-no-properties start (match-beginning 0))))
|
305
|
-
(replace-regexp-in-string "^ " "" str)))))
|
306
|
-
|
307
|
-
(defun vimgolf-setup (status challenge-id)
|
308
|
-
(vimgolf-clear-keystrokes)
|
309
|
-
(setq vimgolf-prior-window-configuration (current-window-configuration)
|
310
|
-
vimgolf-challenge challenge-id)
|
311
|
-
(goto-char (point-min))
|
312
|
-
(let* ((start-text (vimgolf-read-next-data-chunk))
|
313
|
-
(end-text (vimgolf-read-next-data-chunk)))
|
314
|
-
|
315
|
-
(vimgolf-kill-existing-session)
|
316
|
-
|
317
|
-
(let ((vimgolf-start-buffer (get-buffer-create vimgolf-start-buffer-name))
|
318
|
-
(vimgolf-work-buffer (get-buffer-create vimgolf-work-buffer-name))
|
319
|
-
(vimgolf-end-buffer (get-buffer-create vimgolf-end-buffer-name)))
|
320
|
-
|
321
|
-
(vimgolf-init-buffer vimgolf-start-buffer start-text)
|
322
|
-
(vimgolf-init-buffer vimgolf-end-buffer end-text)
|
323
|
-
(with-current-buffer vimgolf-end-buffer (setq buffer-read-only t))
|
324
|
-
(vimgolf-reset-work-buffer)
|
325
|
-
|
326
|
-
;; Set up windows
|
327
|
-
(delete-other-windows)
|
328
|
-
(display-buffer vimgolf-end-buffer 'display-buffer-pop-up-window)
|
329
|
-
(set-window-buffer (selected-window) vimgolf-work-buffer)
|
330
|
-
(switch-to-buffer vimgolf-work-buffer)
|
331
|
-
(setq vimgolf-working-window-configuration (current-window-configuration))
|
332
|
-
|
333
|
-
(vimgolf-continue))))
|
334
|
-
|
335
|
-
(defvar *vimgolf-browse-list* nil
|
336
|
-
"Holds a list of parsed VimGolf challenges.")
|
337
|
-
|
338
|
-
(defun vimgolf-browse (&optional force-pull)
|
339
|
-
(interactive)
|
340
|
-
(if (or (eq *vimgolf-browse-list* nil)
|
341
|
-
force-pull)
|
342
|
-
(url-retrieve vimgolf-host 'vimgolf-parse-browse-html)
|
343
|
-
(vimgolf-browse-list)
|
344
|
-
(vimgolf-browse-next)))
|
345
|
-
|
346
|
-
(defun vimgolf-browse-refresh ()
|
347
|
-
(interactive)
|
348
|
-
(vimgolf-browse t))
|
349
|
-
|
350
|
-
(defun vimgolf-replace-control-m (string &optional replace)
|
351
|
-
(replace-regexp-in-string "
|
352
|
-
|
353
|
-
(defun vimgolf-parse-html-entites (string)
|
354
|
-
(replace-regexp-in-string
|
355
|
-
"<" "<"
|
356
|
-
(replace-regexp-in-string
|
357
|
-
">" ">"
|
358
|
-
(replace-regexp-in-string
|
359
|
-
"&" "&"
|
360
|
-
(replace-regexp-in-string
|
361
|
-
""" "\""
|
362
|
-
string)))))
|
363
|
-
|
364
|
-
(defun vimgolf-parse-browse-html (status)
|
365
|
-
(with-current-buffer (current-buffer)
|
366
|
-
(let ((html (vimgolf-parse-html-entites
|
367
|
-
(replace-regexp-in-string "\n" "" (buffer-string))))
|
368
|
-
(start 0))
|
369
|
-
(setq *vimgolf-browse-list* nil)
|
370
|
-
(while
|
371
|
-
(string-match
|
372
|
-
"<a href=\"/challenges/\\([a-zA-Z0-9]+\\)\">\\(.*?\\)</a>.*?<p>\\(.*?\\)</p>"
|
373
|
-
html)
|
374
|
-
(add-to-list '*vimgolf-browse-list*
|
375
|
-
(cons (match-string 1 html)
|
376
|
-
(list (match-string 2 html)
|
377
|
-
(vimgolf-replace-control-m
|
378
|
-
(match-string 3 html))))
|
379
|
-
t)
|
380
|
-
(setq html (substring html (match-end 0))))
|
381
|
-
*vimgolf-browse-list*))
|
382
|
-
(vimgolf-browse-list)
|
383
|
-
(vimgolf-browse-next))
|
384
|
-
|
385
|
-
(defun vimgolf-browse-list ()
|
386
|
-
(let ((browse-buffer (get-buffer-create "*VimGolf Browse*")))
|
387
|
-
(switch-to-buffer browse-buffer)
|
388
|
-
(setq buffer-read-only nil)
|
389
|
-
(kill-region (point-min) (point-max))
|
390
|
-
(insert "VimGolf Challenges")
|
391
|
-
(newline 2)
|
392
|
-
(dolist (challenge *vimgolf-browse-list*)
|
393
|
-
(let ((title (substring (cadr challenge)
|
394
|
-
0
|
395
|
-
(min (length (cadr challenge))
|
396
|
-
(- fill-column 3))))
|
397
|
-
(description (car (cdr (cdr challenge))))
|
398
|
-
(challenge-id (car challenge)))
|
399
|
-
(when (< (length title) (length (cadr challenge)))
|
400
|
-
(setq title (concat title "...")))
|
401
|
-
(insert-text-button title
|
402
|
-
'action 'vimgolf-browse-select
|
403
|
-
'follow-link t
|
404
|
-
'challenge-id challenge-id
|
405
|
-
'help-echo description))
|
406
|
-
(newline)))
|
407
|
-
(beginning-of-buffer)
|
408
|
-
(vimgolf-browse-mode))
|
409
|
-
|
410
|
-
(defun vimgolf-browse-select (arg)
|
411
|
-
(let ((challenge-id (get-text-property (point) 'challenge-id)))
|
412
|
-
(vimgolf challenge-id)))
|
413
|
-
|
414
|
-
(defun vimgolf-message-title ()
|
415
|
-
(let ((challenge-id (get-text-property (point) 'challenge-id)))
|
416
|
-
(when challenge-id
|
417
|
-
(message (cadr (assoc challenge-id *vimgolf-browse-list*))))))
|
418
|
-
|
419
|
-
(defun vimgolf-browse-next ()
|
420
|
-
(interactive)
|
421
|
-
(goto-char (next-single-property-change (point) 'challenge-id))
|
422
|
-
(unless (get-text-property (point) 'challenge-id)
|
423
|
-
(goto-char (next-single-property-change (point) 'challenge-id)))
|
424
|
-
(vimgolf-message-title))
|
425
|
-
|
426
|
-
(defun vimgolf-browse-previous ()
|
427
|
-
(interactive)
|
428
|
-
(goto-char (previous-single-property-change (point) 'challenge-id))
|
429
|
-
(unless (get-text-property (point) 'challenge-id)
|
430
|
-
(goto-char (previous-single-property-change (point) 'challenge-id)))
|
431
|
-
(vimgolf-message-title))
|
432
|
-
|
433
|
-
(defun vimgolf-show-description ()
|
434
|
-
(interactive)
|
435
|
-
(let ((challenge-id (get-text-property (point) 'challenge-id)))
|
436
|
-
(save-excursion
|
437
|
-
(setq buffer-read-only nil)
|
438
|
-
(if (text-property-any (point-min) (point-max) 'challenge-description challenge-id)
|
439
|
-
(progn
|
440
|
-
(beginning-of-buffer)
|
441
|
-
(while (not (eq (get-text-property (point) 'challenge-description) challenge-id))
|
442
|
-
(goto-char (next-single-property-change (point) 'challenge-description)))
|
443
|
-
(let ((start (point)))
|
444
|
-
(goto-char (next-single-property-change (point) 'challenge-description))
|
445
|
-
(delete-region start (point))
|
446
|
-
(delete-blank-lines)
|
447
|
-
(delete-blank-lines)))
|
448
|
-
(end-of-line)
|
449
|
-
(newline 3)
|
450
|
-
(forward-line -1)
|
451
|
-
(let ((start (point)))
|
452
|
-
(insert " " (car (cddr (assoc challenge-id *vimgolf-browse-list*))))
|
453
|
-
(fill-region start (point))
|
454
|
-
(add-text-properties start (point) `(challenge-description ,challenge-id))))
|
455
|
-
(setq buffer-read-only t))))
|
456
|
-
|
457
|
-
;;;###autoload
|
458
|
-
(defun vimgolf (challenge-id)
|
459
|
-
"Open a VimGolf Challenge"
|
460
|
-
(interactive (list (read-from-minibuffer "Challenge ID: " nil nil nil 'vimgolf-challenge-history)))
|
461
|
-
(url-retrieve (vimgolf-challenge-url challenge-id) 'vimgolf-setup `(,challenge-id)))
|
462
|
-
|
463
|
-
(defvar vimgolf-browse-mode-map (make-sparse-keymap)
|
464
|
-
"Keymap for vimgolf-mode.")
|
465
|
-
|
466
|
-
(define-derived-mode vimgolf-browse-mode special-mode "vimgolf browse"
|
467
|
-
"A major mode for completing vimgolf challenges.
|
468
|
-
|
469
|
-
\\{vimgolf-browse-mode-map}"
|
470
|
-
(define-key vimgolf-browse-mode-map (kbd "TAB") 'vimgolf-show-description)
|
471
|
-
(define-key vimgolf-browse-mode-map "g" 'vimgolf-browse-refresh)
|
472
|
-
(define-key vimgolf-browse-mode-map "n" 'vimgolf-browse-next)
|
473
|
-
(define-key vimgolf-browse-mode-map "p" 'vimgolf-browse-previous)
|
474
|
-
)
|
475
|
-
|
476
|
-
(put 'vimgolf-mode 'mode-class 'special)
|
477
|
-
|
478
|
-
(provide 'vimgolf)
|
479
|
-
|
480
|
-
;;; Local Variables:
|
481
|
-
;;; tab-width:2
|
482
|
-
;;; indent-tabs-mode:nil
|
483
|
-
;;; End:
|
484
|
-
;;; vimgolf.el ends here
|