command-t 3.0.2 → 4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +8 -2
- data/doc/command-t.txt +312 -147
- data/ruby/command-t.rb +13 -12
- data/ruby/command-t/controller.rb +86 -15
- data/ruby/command-t/depend +4 -0
- data/ruby/command-t/ext.h +9 -2
- data/ruby/command-t/extconf.rb +2 -2
- data/ruby/command-t/finder.rb +6 -2
- data/ruby/command-t/finder/buffer_finder.rb +3 -3
- data/ruby/command-t/finder/command_finder.rb +23 -0
- data/ruby/command-t/finder/file_finder.rb +3 -3
- data/ruby/command-t/finder/help_finder.rb +25 -0
- data/ruby/command-t/finder/history_finder.rb +27 -0
- data/ruby/command-t/finder/jump_finder.rb +3 -3
- data/ruby/command-t/finder/line_finder.rb +23 -0
- data/ruby/command-t/finder/mru_buffer_finder.rb +3 -3
- data/ruby/command-t/finder/tag_finder.rb +3 -3
- data/ruby/command-t/heap.c +146 -0
- data/ruby/command-t/heap.h +22 -0
- data/ruby/command-t/match.c +183 -116
- data/ruby/command-t/match.h +16 -10
- data/ruby/command-t/match_window.rb +10 -1
- data/ruby/command-t/matcher.c +203 -63
- data/ruby/command-t/metadata/fallback.rb +2 -2
- data/ruby/command-t/mru.rb +2 -2
- data/ruby/command-t/path_utilities.rb +2 -2
- data/ruby/command-t/progress_reporter.rb +38 -0
- data/ruby/command-t/prompt.rb +4 -4
- data/ruby/command-t/scanner.rb +22 -2
- data/ruby/command-t/scanner/buffer_scanner.rb +3 -3
- data/ruby/command-t/scanner/command_scanner.rb +33 -0
- data/ruby/command-t/scanner/file_scanner.rb +30 -6
- data/ruby/command-t/scanner/file_scanner/find_file_scanner.rb +12 -7
- data/ruby/command-t/scanner/file_scanner/git_file_scanner.rb +11 -8
- data/ruby/command-t/scanner/file_scanner/ruby_file_scanner.rb +7 -4
- data/ruby/command-t/scanner/file_scanner/watchman_file_scanner.rb +13 -5
- data/ruby/command-t/scanner/help_scanner.rb +40 -0
- data/ruby/command-t/scanner/history_scanner.rb +24 -0
- data/ruby/command-t/scanner/jump_scanner.rb +3 -3
- data/ruby/command-t/scanner/line_scanner.rb +45 -0
- data/ruby/command-t/scanner/mru_buffer_scanner.rb +3 -3
- data/ruby/command-t/scanner/tag_scanner.rb +3 -3
- data/ruby/command-t/scm_utilities.rb +2 -2
- data/ruby/command-t/settings.rb +2 -2
- data/ruby/command-t/stub.rb +7 -2
- data/ruby/command-t/util.rb +2 -2
- data/ruby/command-t/vim.rb +27 -2
- data/ruby/command-t/vim/screen.rb +3 -3
- data/ruby/command-t/vim/window.rb +3 -3
- data/ruby/command-t/watchman.c +1 -1
- metadata +13 -2
data/ruby/command-t.rb
CHANGED
@@ -8,16 +8,17 @@ module CommandT
|
|
8
8
|
require 'command-t/metadata/fallback'
|
9
9
|
end
|
10
10
|
|
11
|
-
autoload :Controller,
|
12
|
-
autoload :Finder,
|
13
|
-
autoload :MRU,
|
14
|
-
autoload :MatchWindow,
|
11
|
+
autoload :Controller, 'command-t/controller'
|
12
|
+
autoload :Finder, 'command-t/finder'
|
13
|
+
autoload :MRU, 'command-t/mru'
|
14
|
+
autoload :MatchWindow, 'command-t/match_window'
|
15
15
|
autoload :PathUtilities, 'command-t/path_utilities'
|
16
|
-
autoload :
|
17
|
-
autoload :
|
18
|
-
autoload :
|
19
|
-
autoload :
|
20
|
-
autoload :
|
21
|
-
autoload :
|
22
|
-
autoload :
|
23
|
-
|
16
|
+
autoload :ProgressReporter, 'command-t/progress_reporter'
|
17
|
+
autoload :Prompt, 'command-t/prompt'
|
18
|
+
autoload :SCMUtilities, 'command-t/scm_utilities'
|
19
|
+
autoload :Scanner, 'command-t/scanner'
|
20
|
+
autoload :Settings, 'command-t/settings'
|
21
|
+
autoload :Stub, 'command-t/stub'
|
22
|
+
autoload :Util, 'command-t/util'
|
23
|
+
autoload :VIM, 'command-t/vim'
|
24
|
+
end
|
@@ -67,6 +67,27 @@ module CommandT
|
|
67
67
|
end
|
68
68
|
guard :show_buffer_finder
|
69
69
|
|
70
|
+
def show_command_finder
|
71
|
+
@path = VIM::pwd
|
72
|
+
@active_finder = command_finder
|
73
|
+
show
|
74
|
+
end
|
75
|
+
guard :show_command_finder
|
76
|
+
|
77
|
+
def show_help_finder
|
78
|
+
@path = VIM::pwd
|
79
|
+
@active_finder = help_finder
|
80
|
+
show
|
81
|
+
end
|
82
|
+
guard :show_help_finder
|
83
|
+
|
84
|
+
def show_history_finder
|
85
|
+
@path = VIM::pwd
|
86
|
+
@active_finder = history_finder
|
87
|
+
show
|
88
|
+
end
|
89
|
+
guard :show_history_finder
|
90
|
+
|
70
91
|
def show_jump_finder
|
71
92
|
@path = VIM::pwd
|
72
93
|
@active_finder = jump_finder
|
@@ -74,6 +95,13 @@ module CommandT
|
|
74
95
|
end
|
75
96
|
guard :show_jump_finder
|
76
97
|
|
98
|
+
def show_line_finder
|
99
|
+
@path = VIM::pwd
|
100
|
+
@active_finder = line_finder
|
101
|
+
show
|
102
|
+
end
|
103
|
+
guard :show_line_finder
|
104
|
+
|
77
105
|
def show_mru_finder
|
78
106
|
@path = VIM::pwd
|
79
107
|
@active_finder = mru_finder
|
@@ -81,6 +109,13 @@ module CommandT
|
|
81
109
|
end
|
82
110
|
guard :show_mru_finder
|
83
111
|
|
112
|
+
def show_search_finder
|
113
|
+
@path = VIM::pwd
|
114
|
+
@active_finder = search_finder
|
115
|
+
show
|
116
|
+
end
|
117
|
+
guard :show_search_finder
|
118
|
+
|
84
119
|
def show_tag_finder
|
85
120
|
@path = VIM::pwd
|
86
121
|
@active_finder = tag_finder
|
@@ -161,7 +196,7 @@ module CommandT
|
|
161
196
|
key = ::VIM::evaluate('a:arg').to_i.chr
|
162
197
|
if @focus == prompt
|
163
198
|
prompt.add! key
|
164
|
-
|
199
|
+
update
|
165
200
|
else
|
166
201
|
@match_window.find key
|
167
202
|
end
|
@@ -171,7 +206,7 @@ module CommandT
|
|
171
206
|
def backspace
|
172
207
|
if @focus == prompt
|
173
208
|
prompt.backspace!
|
174
|
-
|
209
|
+
update
|
175
210
|
end
|
176
211
|
end
|
177
212
|
guard :backspace
|
@@ -179,7 +214,7 @@ module CommandT
|
|
179
214
|
def delete
|
180
215
|
if @focus == prompt
|
181
216
|
prompt.delete!
|
182
|
-
|
217
|
+
update
|
183
218
|
end
|
184
219
|
end
|
185
220
|
guard :delete
|
@@ -266,6 +301,9 @@ module CommandT
|
|
266
301
|
)
|
267
302
|
@match_window.matches = @matches
|
268
303
|
|
304
|
+
# Scanner may have overwritten prompt to show progress.
|
305
|
+
prompt.redraw
|
306
|
+
|
269
307
|
@needs_update = false
|
270
308
|
end
|
271
309
|
guard :list_matches
|
@@ -284,6 +322,14 @@ module CommandT
|
|
284
322
|
|
285
323
|
private
|
286
324
|
|
325
|
+
def update
|
326
|
+
if @debounce_interval > 0
|
327
|
+
@needs_update = true
|
328
|
+
else
|
329
|
+
list_matches!
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
287
333
|
def prompt
|
288
334
|
@prompt ||= Prompt.new(
|
289
335
|
:cursor_color => VIM::get_string('g:CommandTCursorColor')
|
@@ -302,14 +348,16 @@ module CommandT
|
|
302
348
|
end
|
303
349
|
|
304
350
|
def show
|
305
|
-
@initial_window
|
306
|
-
@initial_buffer
|
307
|
-
@
|
351
|
+
@initial_window = $curwin
|
352
|
+
@initial_buffer = $curbuf
|
353
|
+
@debounce_interval = VIM::get_number('g:CommandTInputDebounce') || 0
|
354
|
+
@match_window = MatchWindow.new \
|
355
|
+
:encoding => VIM::get_string('g:CommandTEncoding'),
|
308
356
|
:highlight_color => VIM::get_string('g:CommandTHighlightColor'),
|
309
357
|
:match_window_at_top => VIM::get_bool('g:CommandTMatchWindowAtTop'),
|
310
358
|
:match_window_reverse => VIM::get_bool('g:CommandTMatchWindowReverse', true),
|
311
359
|
:min_height => min_height,
|
312
|
-
:debounce_interval =>
|
360
|
+
:debounce_interval => @debounce_interval,
|
313
361
|
:prompt => prompt,
|
314
362
|
:name => "Command-T [#{@active_finder.name}]"
|
315
363
|
@focus = prompt
|
@@ -422,8 +470,9 @@ module CommandT
|
|
422
470
|
numbers = ('0'..'9').to_a.join
|
423
471
|
lowercase = ('a'..'z').to_a.join
|
424
472
|
uppercase = lowercase.upcase
|
425
|
-
punctuation = '<>`@#~!"
|
426
|
-
|
473
|
+
punctuation = '<>`@#~!"$%^&/()=+*-_.,;:?\\|\'{}[]'
|
474
|
+
space = ' '
|
475
|
+
(numbers + lowercase + uppercase + punctuation + space).each_byte do |b|
|
427
476
|
map "<Char-#{b}>", 'HandleKey', b
|
428
477
|
end
|
429
478
|
|
@@ -463,10 +512,12 @@ module CommandT
|
|
463
512
|
end
|
464
513
|
|
465
514
|
def set_up_autocmds
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
515
|
+
if @debounce_interval > 0
|
516
|
+
::VIM::command 'augroup CommandTController'
|
517
|
+
::VIM::command 'autocmd!'
|
518
|
+
::VIM::command 'autocmd CursorHold <buffer> :call commandt#private#ListMatches()'
|
519
|
+
::VIM::command 'augroup END'
|
520
|
+
end
|
470
521
|
end
|
471
522
|
|
472
523
|
# Returns the desired maximum number of matches, based on available vertical
|
@@ -485,6 +536,10 @@ module CommandT
|
|
485
536
|
@buffer_finder ||= CommandT::Finder::BufferFinder.new
|
486
537
|
end
|
487
538
|
|
539
|
+
def command_finder
|
540
|
+
@command_finder ||= CommandT::Finder::CommandFinder.new
|
541
|
+
end
|
542
|
+
|
488
543
|
def mru_finder
|
489
544
|
@mru_finder ||= CommandT::Finder::MRUBufferFinder.new
|
490
545
|
end
|
@@ -502,13 +557,29 @@ module CommandT
|
|
502
557
|
:git_scan_submodules => VIM::get_bool('g:CommandTGitScanSubmodules')
|
503
558
|
end
|
504
559
|
|
560
|
+
def help_finder
|
561
|
+
@jump_finder ||= CommandT::Finder::HelpFinder.new
|
562
|
+
end
|
563
|
+
|
564
|
+
def history_finder
|
565
|
+
CommandT::Finder::HistoryFinder.new(:history_type => ':')
|
566
|
+
end
|
567
|
+
|
505
568
|
def jump_finder
|
506
569
|
@jump_finder ||= CommandT::Finder::JumpFinder.new
|
507
570
|
end
|
508
571
|
|
572
|
+
def line_finder
|
573
|
+
CommandT::Finder::LineFinder.new
|
574
|
+
end
|
575
|
+
|
576
|
+
def search_finder
|
577
|
+
CommandT::Finder::HistoryFinder.new(:history_type => '/')
|
578
|
+
end
|
579
|
+
|
509
580
|
def tag_finder
|
510
581
|
@tag_finder ||= CommandT::Finder::TagFinder.new \
|
511
582
|
:include_filenames => VIM::get_bool('g:CommandTTagIncludeFilenames')
|
512
583
|
end
|
513
|
-
end
|
514
|
-
end
|
584
|
+
end
|
585
|
+
end
|
data/ruby/command-t/depend
CHANGED
data/ruby/command-t/ext.h
CHANGED
@@ -13,5 +13,12 @@ extern VALUE mCommandTWatchmanUtils; // module CommandT::Watchman::Utils
|
|
13
13
|
// raised if it is not nil and not a hash.
|
14
14
|
VALUE CommandT_option_from_hash(const char *option, VALUE hash);
|
15
15
|
|
16
|
-
// Debugging
|
17
|
-
#define
|
16
|
+
// Debugging macros.
|
17
|
+
#define L(...) { \
|
18
|
+
fprintf(stdout, __VA_ARGS__); \
|
19
|
+
fflush(stdout); \
|
20
|
+
} while (0)
|
21
|
+
#define RUBY_INSPECT(obj) do { \
|
22
|
+
rb_funcall(rb_mKernel, rb_intern("p"), 1, obj); \
|
23
|
+
fflush(stdout); \
|
24
|
+
} while (0)
|
data/ruby/command-t/extconf.rb
CHANGED
data/ruby/command-t/finder.rb
CHANGED
@@ -12,8 +12,12 @@ module CommandT
|
|
12
12
|
# different kinds of search (files, buffers).
|
13
13
|
class Finder
|
14
14
|
autoload :BufferFinder, 'command-t/finder/buffer_finder'
|
15
|
+
autoload :CommandFinder, 'command-t/finder/command_finder'
|
15
16
|
autoload :FileFinder, 'command-t/finder/file_finder'
|
17
|
+
autoload :HelpFinder, 'command-t/finder/help_finder'
|
18
|
+
autoload :HistoryFinder, 'command-t/finder/history_finder'
|
16
19
|
autoload :JumpFinder, 'command-t/finder/jump_finder'
|
20
|
+
autoload :LineFinder, 'command-t/finder/line_finder'
|
17
21
|
autoload :MRUBufferFinder, 'command-t/finder/mru_buffer_finder'
|
18
22
|
autoload :TagFinder, 'command-t/finder/tag_finder'
|
19
23
|
|
@@ -42,5 +46,5 @@ module CommandT
|
|
42
46
|
def path=(path)
|
43
47
|
@scanner.path = path
|
44
48
|
end
|
45
|
-
end
|
46
|
-
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright 2011-present Greg Hurrell. All rights reserved.
|
2
|
+
# Licensed under the terms of the BSD 2-clause license.
|
3
|
+
|
4
|
+
module CommandT
|
5
|
+
class Finder
|
6
|
+
class CommandFinder < Finder
|
7
|
+
def initialize(options = {})
|
8
|
+
@scanner = Scanner::CommandScanner.new
|
9
|
+
@matcher = Matcher.new @scanner, :always_show_dot_files => true
|
10
|
+
end
|
11
|
+
|
12
|
+
def open_selection(command, selection, options = {})
|
13
|
+
::VIM::command "call feedkeys(':#{selection} ', 'nt')"
|
14
|
+
end
|
15
|
+
|
16
|
+
def flush; end
|
17
|
+
|
18
|
+
def name
|
19
|
+
'Commands'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Copyright 2011-present Greg Hurrell. All rights reserved.
|
2
|
+
# Licensed under the terms of the BSD 2-clause license.
|
3
|
+
|
4
|
+
module CommandT
|
5
|
+
class Finder
|
6
|
+
class HelpFinder < Finder
|
7
|
+
def initialize(options = {})
|
8
|
+
@scanner = Scanner::HelpScanner.new
|
9
|
+
@matcher = Matcher.new @scanner, :always_show_dot_files => true
|
10
|
+
end
|
11
|
+
|
12
|
+
def open_selection(command, selection, options = {})
|
13
|
+
::VIM::command "help #{selection}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def flush
|
17
|
+
@scanner.flush
|
18
|
+
end
|
19
|
+
|
20
|
+
def name
|
21
|
+
'Help'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Copyright 2011-present Greg Hurrell. All rights reserved.
|
2
|
+
# Licensed under the terms of the BSD 2-clause license.
|
3
|
+
|
4
|
+
module CommandT
|
5
|
+
class Finder
|
6
|
+
class HistoryFinder < Finder
|
7
|
+
def initialize(options = {})
|
8
|
+
@history_type = options[:history_type] # / or :
|
9
|
+
@scanner = Scanner::HistoryScanner.new("silent history #{@history_type}")
|
10
|
+
@matcher = Matcher.new @scanner, :always_show_dot_files => true
|
11
|
+
end
|
12
|
+
|
13
|
+
def open_selection(command, selection, options = {})
|
14
|
+
# Need to unescape to reverse the work done by `#sanitize_path_string`.
|
15
|
+
unescaped = selection.gsub(/\\(.)/, '\1')
|
16
|
+
escaped = VIM.escape_for_single_quotes unescaped
|
17
|
+
::VIM::command "call feedkeys('#{@history_type}#{escaped} ', 'nt')"
|
18
|
+
end
|
19
|
+
|
20
|
+
def flush; end
|
21
|
+
|
22
|
+
def name
|
23
|
+
@history_type == ':' ? 'History' : 'Searches'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright 2011-present Greg Hurrell. All rights reserved.
|
2
|
+
# Licensed under the terms of the BSD 2-clause license.
|
3
|
+
|
4
|
+
module CommandT
|
5
|
+
class Finder
|
6
|
+
class LineFinder < Finder
|
7
|
+
def initialize(options = {})
|
8
|
+
@scanner = Scanner::LineScanner.new
|
9
|
+
@matcher = Matcher.new @scanner, :always_show_dot_files => true
|
10
|
+
end
|
11
|
+
|
12
|
+
def open_selection(command, selection, options = {})
|
13
|
+
::VIM::command "#{selection.sub(/.+:(\d+)$/, '\1')}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def flush; end
|
17
|
+
|
18
|
+
def name
|
19
|
+
'Lines'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
// Copyright 2016-present Greg Hurrell. All rights reserved.
|
2
|
+
// Licensed under the terms of the BSD 2-clause license.
|
3
|
+
|
4
|
+
#include <stdlib.h> /* for free(), malloc(), NULL */
|
5
|
+
|
6
|
+
#include "heap.h"
|
7
|
+
|
8
|
+
#define HEAP_PARENT(index) ((index - 1) / 2)
|
9
|
+
#define HEAP_LEFT(index) (2 * index + 1)
|
10
|
+
#define HEAP_RIGHT(index) (2 * index + 2)
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Returns a new heap, or NULL on failure.
|
14
|
+
*/
|
15
|
+
heap_t *heap_new(long capacity, heap_compare_entries comparator) {
|
16
|
+
heap_t *heap = malloc(sizeof(heap_t));
|
17
|
+
if (!heap) {
|
18
|
+
return NULL;
|
19
|
+
}
|
20
|
+
heap->capacity = capacity;
|
21
|
+
heap->comparator = comparator;
|
22
|
+
heap->count = 0;
|
23
|
+
|
24
|
+
heap->entries = malloc(capacity * sizeof(void *));
|
25
|
+
if (!heap->entries) {
|
26
|
+
free(heap);
|
27
|
+
return NULL;
|
28
|
+
}
|
29
|
+
return heap;
|
30
|
+
}
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Frees a previously created heap.
|
34
|
+
*/
|
35
|
+
void heap_free(heap_t *heap) {
|
36
|
+
free(heap->entries);
|
37
|
+
free(heap);
|
38
|
+
}
|
39
|
+
|
40
|
+
/**
|
41
|
+
* @internal
|
42
|
+
*
|
43
|
+
* Compare values at indices `a_idx` and `b_idx` using the heap's comparator
|
44
|
+
* function.
|
45
|
+
*/
|
46
|
+
int heap_compare(heap_t *heap, long a_idx, long b_idx) {
|
47
|
+
const void *a = heap->entries[a_idx];
|
48
|
+
const void *b = heap->entries[b_idx];
|
49
|
+
return heap->comparator(a, b);
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* @internal
|
54
|
+
*
|
55
|
+
* Returns 1 if the heap property holds (ie. parent < child).
|
56
|
+
*/
|
57
|
+
int heap_property(heap_t *heap, long parent_idx, long child_idx) {
|
58
|
+
return heap_compare(heap, parent_idx, child_idx) > 0;
|
59
|
+
}
|
60
|
+
|
61
|
+
/**
|
62
|
+
* @internal
|
63
|
+
*
|
64
|
+
* Swaps the values at indexes `a` and `b` within `heap`.
|
65
|
+
*/
|
66
|
+
void heap_swap(heap_t *heap, long a, long b) {
|
67
|
+
void *tmp = heap->entries[a];
|
68
|
+
heap->entries[a] = heap->entries[b];
|
69
|
+
heap->entries[b] = tmp;
|
70
|
+
}
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Inserts `value` into `heap`.
|
74
|
+
*/
|
75
|
+
void heap_insert(heap_t *heap, void *value) {
|
76
|
+
long idx, parent_idx;
|
77
|
+
|
78
|
+
// If at capacity, ignore.
|
79
|
+
if (heap->count == heap->capacity) {
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
|
83
|
+
// Insert into first empty slot.
|
84
|
+
idx = heap->count;
|
85
|
+
heap->entries[idx] = value;
|
86
|
+
heap->count++;
|
87
|
+
|
88
|
+
// Bubble upwards until heap property is restored.
|
89
|
+
parent_idx = HEAP_PARENT(idx);
|
90
|
+
while (idx && !heap_property(heap, parent_idx, idx)) {
|
91
|
+
heap_swap(heap, idx, parent_idx);
|
92
|
+
idx = parent_idx;
|
93
|
+
parent_idx = HEAP_PARENT(idx);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* @internal
|
99
|
+
*
|
100
|
+
* Restores the heap property starting at `idx`.
|
101
|
+
*/
|
102
|
+
void heap_heapify(heap_t *heap, long idx) {
|
103
|
+
long left_idx = HEAP_LEFT(idx);
|
104
|
+
long right_idx = HEAP_RIGHT(idx);
|
105
|
+
long smallest_idx =
|
106
|
+
right_idx < heap->count ?
|
107
|
+
|
108
|
+
// Right (and therefore left) child exists.
|
109
|
+
(heap_compare(heap, left_idx, right_idx) > 0 ? left_idx : right_idx) :
|
110
|
+
|
111
|
+
left_idx < heap->count ?
|
112
|
+
|
113
|
+
// Only left child exists.
|
114
|
+
left_idx :
|
115
|
+
|
116
|
+
// No children exist.
|
117
|
+
idx;
|
118
|
+
|
119
|
+
if (
|
120
|
+
smallest_idx != idx &&
|
121
|
+
!heap_property(heap, idx, smallest_idx)
|
122
|
+
) {
|
123
|
+
// Swap with smallest_idx child.
|
124
|
+
heap_swap(heap, idx, smallest_idx);
|
125
|
+
heap_heapify(heap, smallest_idx);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
/**
|
130
|
+
* Extracts the minimum value from `heap`.
|
131
|
+
*/
|
132
|
+
void *heap_extract(heap_t *heap) {
|
133
|
+
void *extracted = NULL;
|
134
|
+
if (heap->count) {
|
135
|
+
// Grab root value.
|
136
|
+
extracted = heap->entries[0];
|
137
|
+
|
138
|
+
// Move last item to root.
|
139
|
+
heap->entries[0] = heap->entries[heap->count - 1];
|
140
|
+
heap->count--;
|
141
|
+
|
142
|
+
// Restore heap property.
|
143
|
+
heap_heapify(heap, 0);
|
144
|
+
}
|
145
|
+
return extracted;
|
146
|
+
}
|