Exemplo n.º 1
0
def handle_midi_input(msg):
    # Only handle the message if the piano has the focus; could also find the
    # piano view in the window as the other command does. Note: there is not
    # always an active view.
    view = sublime.active_window().active_view()
    if not view:
        return

    listener = sublime_plugin.find_view_event_listener(view, Piano)
    if listener:
        # Ship the message over; this will play notes, but also allow for
        # program changes, etc. This lets incoming velocity and aftertouch
        # information through without the event listener needing to  synthesize
        # them
        out_port.send(msg)

        # For note messges, we want to synthesize the display.
        if msg.type.startswith('note_'):
            octave, note = PianoMidi.midi_note_to_note(msg.note)

            # Per the specs, note_on with a velocity of 0 should be interpreted
            # as note_off; if that happens replace the message so the display
            # will update.
            if msg.type == 'note_on' and msg.velocity == 0:
                msg = mido.Message('note_off', note=msg.note, time=msg.time)

            # Get the listener to update the display but not play the note.
            sublime.set_timeout(lambda: getattr(listener, msg.type)(octave, note, False))

        return True

    return False
Exemplo n.º 2
0
    def run(self, edit):
        view = self.view
        cursor = view.sel()[0]

        listener = sublime_plugin.find_view_event_listener(
            view, SyntaxTestHighlighterListener)

        details = listener.get_details_of_test_assertion_line(cursor.begin())
        if not details.comment_marker_match:
            return

        # find the last test assertion column on the previous line
        details = listener.get_details_of_test_assertion_line(
            details.line_region.begin() - 1)
        next_col = None
        if not details.assertion_colrange:
            # the previous line wasn't a syntax test line, so instead
            # find the first non-whitespace char on the line being tested above
            for pos in range(details.line_region.begin(),
                             details.line_region.end()):
                if view.substr(pos).strip() != '':
                    break
            next_col = view.rowcol(pos)[1]
        else:
            next_col = details.assertion_colrange[1]
        col_diff = next_col - view.rowcol(cursor.begin())[1]
        view.insert(edit, cursor.end(), " " * col_diff)
        view.run_command('suggest_syntax_test')
Exemplo n.º 3
0
    def run(self, edit):
        view = self.view
        cursor = view.sel()[0]

        listener = sublime_plugin.find_view_event_listener(view, SyntaxTestHighlighterListener)

        details = listener.get_details_of_test_assertion_line(cursor.begin())
        if not details.comment_marker_match:
            return

        # find the last test assertion column on the previous line
        details = listener.get_details_of_test_assertion_line(details.line_region.begin() - 1)
        next_col = None
        skip_whitespace = get_setting('syntax_test.skip_whitespace', True)
        if details.assertion_colrange:
            next_col = details.assertion_colrange[1]
        else:
            # the previous line wasn't a syntax test line, so instead
            # start at the first position on the line. We will then
            # advance to the first non-whitespace char on the line.
            next_col = 0
            skip_whitespace = True

        # find the next non-whitespace char on the line being tested above
        if skip_whitespace:
            line_region = listener.get_details_of_line_being_tested()[1]
            pos = line_region.begin() + next_col
            for pos in range(pos, line_region.end()):
                if view.substr(pos).strip() != '':
                    break
            next_col = view.rowcol(pos)[1]

        col_diff = next_col - view.rowcol(cursor.begin())[1]
        view.insert(edit, cursor.end(), " " * col_diff)
        view.run_command('packagedev_suggest_syntax_test')
Exemplo n.º 4
0
    def run(self, edit, character):
        listener = sublime_plugin.find_view_event_listener(self.view, Piano)

        try:
            index = piano_prefs('keyboard_keys').index(character)
        except ValueError:
            return

        # left most key in the list starts at octave 3
        # TODO: base this on how many keys are in the list?
        #       or on the piano's start octave?
        #       - ideally we would show the keys on the piano to make it clear
        octave = 3 + index // len(PianoMidi.notes_solfege)
        note_index = index % len(PianoMidi.notes_solfege)

        note = (octave, note_index)
        # if the note is already playing, just extend the time out rather than playing it again
        if note in self.active_notes.keys():
            self.active_notes[note] += 1
            timeout = 96
        else:
            self.active_notes[note] = 1
            timeout = 500 # key repeat delay
            listener.note_on(octave, note_index)
        sublime.set_timeout_async(lambda: self.stop_or_extend_note(note), timeout)
Exemplo n.º 5
0
    def run(self, edit, character='^'):
        """Available parameters:
        edit (sublime.Edit)
            The edit parameter from TextCommand.
        character (str) = '^'
            The character to insert when suggesting where the test assertions should go.
        """

        view = self.view
        view.replace(edit, view.sel()[0], character)
        insert_at = view.sel()[0].begin()
        _, col = view.rowcol(insert_at)

        listener = sublime_plugin.find_view_event_listener(
            view, SyntaxTestHighlighterListener)
        if not listener.header:
            return

        lines, line = listener.get_details_of_line_being_tested()
        if not lines[-1].assertion_colrange:
            return
        end_token = listener.header.comment_end
        # don't duplicate the end token if it is on the line but not selected
        if end_token and view.sel()[0].end() == lines[0].line_region.end():
            end_token = ' ' + end_token
        else:
            end_token = ''

        if character == '-':
            length = 1
            scopes = {
                view.scope_name(line.begin() + lines[0].assertion_colrange[0])
            }
        elif character == '^':
            length, scopes = self.determine_test_extends(lines, line, col)
        else:
            return

        suggest_suffix = get_setting('syntax_test.suggest_scope_suffix', True)
        scope = find_common_scopes(scopes, not suggest_suffix)

        # delete the existing selection
        if not view.sel()[0].empty():
            view.erase(edit, view.sel()[0])

        view.insert(edit, insert_at,
                    (character * max(1, length)) + ' ' + scope + end_token)

        # move the selection to cover the added scope name,
        # so that the user can easily insert another ^ to extend the test
        view.sel().clear()
        view.sel().add(
            sublime.Region(insert_at + length,
                           insert_at + length + len(' ' + scope + end_token)))
Exemplo n.º 6
0
    def on_post_text_command(self, view, command_name, args):
        if command_name == 'hide_auto_complete':
            listener = sublime_plugin.find_view_event_listener(view, SettingsListener)
            if listener:
                listener.is_completing_key = False
        elif command_name in ('commit_completion', 'insert_best_completion'):
            listener = sublime_plugin.find_view_event_listener(view, SettingsListener)
            if not (listener and listener.is_completing_key):
                return

            listener.is_completing_key = False
            sel = view.sel()
            if len(sel) != 1:
                # unclear what to do, so just do nothing
                return
            point = sel[0].begin()
            key_region = get_last_key_region(view, point)
            if key_region:
                key = view.substr(key_region)
                logger.debug("showing popup after inserting key completion for %r", key)
                listener.show_popup_for(key_region)
Exemplo n.º 7
0
    def on_post_text_command(self, view, command_name, args):
        if command_name == 'hide_auto_complete':
            listener = sublime_plugin.find_view_event_listener(view, SettingsListener)
            if listener:
                listener.is_completing_key = False
        elif command_name in ('commit_completion', 'insert_best_completion'):
            listener = sublime_plugin.find_view_event_listener(view, SettingsListener)
            if not (listener and listener.is_completing_key):
                return

            listener.is_completing_key = False
            sel = view.sel()
            if len(sel) != 1:
                # unclear what to do, so just do nothing
                return
            point = sel[0].begin()
            key_region = get_last_key_region(view, point)
            if key_region:
                key = view.substr(key_region)
                l.debug("showing popup after inserting key completion for %r", key)
                listener.show_popup_for(key_region)
Exemplo n.º 8
0
    def run(self, edit):
        self.view.run_command("commit_completion")

        # Don't add duplicated dot, if scope is edited in the middle.
        if self.view.substr(self.view.sel()[0].a) == ".":
            return

        # Check if the completed value was the base suffix
        # and don't re-open auto complete in that case.
        listener = sublime_plugin.find_view_event_listener(self.view, SyntaxDefCompletionsListener)
        if listener and listener.base_suffix:
            point = self.view.sel()[0].a
            region = sublime.Region(point - len(listener.base_suffix) - 1, point)
            if self.view.substr(region) == "." + listener.base_suffix:
                return

        # Insert a . and trigger next completion
        self.view.run_command('insert', {'characters': "."})
        self.view.run_command('auto_complete', {'disable_auto_insert': True})
Exemplo n.º 9
0
    def run(self, edit):
        self.view.run_command("commit_completion")

        # Don't add duplicated dot, if scope is edited in the middle.
        if self.view.substr(self.view.sel()[0].a) == ".":
            return

        # Check if the completed value was the base suffix
        # and don't re-open auto complete in that case.
        listener = sublime_plugin.find_view_event_listener(self.view, SyntaxDefCompletionsListener)
        if listener and listener.base_suffix:
            point = self.view.sel()[0].a
            region = sublime.Region(point - len(listener.base_suffix) - 1, point)
            if self.view.substr(region) == "." + listener.base_suffix:
                return

        # Insert a . and trigger next completion
        self.view.run_command('insert', {'characters': "."})
        self.view.run_command('auto_complete', {'disable_auto_insert': True})
Exemplo n.º 10
0
    def run(self, edit):
        view = self.view
        listener = sublime_plugin.find_view_event_listener(
            view, SyntaxTestHighlighterListener)
        if not listener.header:
            return

        suggest_suffix = get_setting('syntax_test.suggest_scope_suffix', True)

        for region in reversed(view.sel()):
            line = view.line(region.b)

            forest = ScopeTreeNode.build_forest(
                view.extract_tokens_with_scopes(line),
                trim_suffix=not suggest_suffix,
            )

            tests = self.get_test_lines(forest, listener.header, line.begin())

            view.insert(edit, line.end(), ''.join(tests))
Exemplo n.º 11
0
    def run(self, edit):
        listener = sublime_plugin.find_view_event_listener(self.view, PianoTune)
        # take the notes from the selection or entire buffer
        regions = self.view.sel()
        if len(regions) == 1 and regions[0].empty():
            regions = [sublime.Region(0, self.view.size())]
        # TODO: when playing a selection, should it automatically find the octave and tempo, from before the selection, or expect the user to select those too?
        # TODO: think about how left hand vs right hand vs both hand playing could work
        #       - should they be in separate files, or marked up in a single file?
        #         - maybe easier to understand the files if separate, especially with labels etc.
        # TODO: a mode where only the keys light up without the sound playing
        #       - and a mode where it waits for the user to press the key before continuing on
        #         - here the left and right hand (i.e. if user is playing right hand and left is on auto-play) need to stay synced up
        tokens = piano_tunes.parse_piano_tune(piano_tunes.get_tokens_from_regions(self.view, regions))
        #print(list(tokens))
        states = piano_tunes.resolve_piano_tune_instructions(tokens)

        midi_messages = piano_tunes.convert_piano_tune_to_midi(states)
        #from pprint import pprint
        #midi_messages = list(midi_messages); pprint(midi_messages)

        listener.play_midi_instructions(midi_messages)
Exemplo n.º 12
0
    def run(self, edit, character='^'):
        """Available parameters:
        edit (sublime.Edit)
            The edit parameter from TextCommand.
        character (str) = '^'
            The character to insert when suggesting where the test assertions should go.
        """

        view = self.view
        view.replace(edit, view.sel()[0], character)
        insert_at = view.sel()[0].begin()

        listener = sublime_plugin.find_view_event_listener(view, SyntaxTestHighlighterListener)
        if not listener.header:
            return

        lines, line = listener.get_details_of_line_being_tested()
        end_token = listener.header.comment_end
        # don't duplicate the end token if it is on the line but not selected
        if end_token and view.sel()[0].end() == lines[0].line_region.end():
            end_token = ' ' + end_token
        else:
            end_token = ''

        scopes = []
        length = 0
        # find the following columns on the line to be tested where the scopes don't change
        test_at_start_of_comment = False
        col = view.rowcol(insert_at)[1]
        assertion_colrange = lines[0].assertion_colrange or (-1, -1)
        if assertion_colrange[0] == assertion_colrange[1]:
            col = assertion_colrange[1]
            test_at_start_of_comment = True
            lines = lines[1:]

        col_start, col_end = lines[0].assertion_colrange
        base_scope = path.commonprefix([
            view.scope_name(pos)
            for pos in range(line.begin() + col_start, line.begin() + col_end)
        ])

        for pos in range(line.begin() + col, line.end() + 1):
            scope = view.scope_name(pos)
            if len(scopes) == 0:
                scopes.append(scope)
            elif not scope.startswith(base_scope):
                break
            length += 1
            if test_at_start_of_comment:
                break

        # find the unique scopes at each existing assertion position
        if lines and not test_at_start_of_comment:
            col_start, col_end = lines[0].assertion_colrange
            for pos in range(line.begin() + col_start, line.begin() + col_end):
                scope = view.scope_name(pos)
                if scope not in scopes:
                    scopes.append(scope)

        suggest_suffix = get_setting('syntax_test.suggest_scope_suffix', True)

        scope = find_common_scopes(scopes, not suggest_suffix)

        # delete the existing selection
        if not view.sel()[0].empty():
            view.erase(edit, view.sel()[0])

        view.insert(edit, insert_at, (character * max(1, length)) + ' ' + scope + end_token)

        # move the selection to cover the added scope name,
        # so that the user can easily insert another ^ to extend the test
        view.sel().clear()
        view.sel().add(sublime.Region(
            insert_at + length,
            insert_at + length + len(' ' + scope + end_token)
        ))
Exemplo n.º 13
0
 def is_enabled(self):
     listener = sublime_plugin.find_view_event_listener(
         self.view,
         SyntaxTestHighlighterListener,
     )
     return bool(listener and listener.header)
Exemplo n.º 14
0
 def on_post_save(self, view):
     listener = sublime_plugin.find_view_event_listener(view, SettingsListener)
     if listener and listener.known_settings:
         listener.known_settings.trigger_settings_reload()
Exemplo n.º 15
0
 def play_note(self, parse_state):
     note_index = parse_state.instruction.value
     listener = sublime_plugin.find_view_event_listener(self.view, PianoTune)
     listener.play_note_with_duration(parse_state.current_octave, note_index, parse_state.duration)
Exemplo n.º 16
0
 def find_piano(self):
     piano = get_piano_view()
     if piano:
         return sublime_plugin.find_view_event_listener(piano, Piano)
Exemplo n.º 17
0
 def is_enabled(self):
     listener = sublime_plugin.find_view_event_listener(self.view, PianoTune)
     return listener is not None
Exemplo n.º 18
0
 def run(self, edit):
     listener = sublime_plugin.find_view_event_listener(self.view, PianoTune)
     listener.playback_stopped = True
Exemplo n.º 19
0
 def is_enabled(self):
     listener = sublime_plugin.find_view_event_listener(self.view, PianoTune)
     return listener is not None and not listener.playback_stopped
Exemplo n.º 20
0
    def run(self, edit, character='^'):
        """Available parameters:
        edit (sublime.Edit)
            The edit parameter from TextCommand.
        character (str) = '^'
            The character to insert when suggesting where the test assertions should go.
        """

        view = self.view
        view.replace(edit, view.sel()[0], character)
        insert_at = view.sel()[0].begin()
        _, col = view.rowcol(insert_at)

        listener = sublime_plugin.find_view_event_listener(view, SyntaxTestHighlighterListener)
        if not listener.header:
            return

        lines, line = listener.get_details_of_line_being_tested()
        if not lines[-1].assertion_colrange:
            return
        end_token = listener.header.comment_end
        # don't duplicate the end token if it is on the line but not selected
        if end_token and view.sel()[0].end() == lines[0].line_region.end():
            end_token = ' ' + end_token
        else:
            end_token = ''

        if character == '-':
            length = 1
            scopes = {view.scope_name(line.begin() + lines[0].assertion_colrange[0])}
        elif character == '^':
            length, scopes = self.determine_test_extends(lines, line, col)
        else:
            return

        suggest_suffix = get_setting('syntax_test.suggest_scope_suffix', True)
        scope = find_common_scopes(scopes, not suggest_suffix)

        trim_prefix = not get_setting('syntax_test.suggest_asserted_prefix', False)
        if trim_prefix:
            scopes_above = [
                self.view.substr(sublime.Region(
                    line.line_region.begin() + line.assertion_colrange[1],
                    line.line_region.end(),
                )).strip()
                for line in lines[1:]
                if line.assertion_colrange[0] <= lines[0].assertion_colrange[0]
                and line.assertion_colrange[1] >= lines[0].assertion_colrange[1]
            ]

            for scope_above in reversed(scopes_above):
                # Determine the last scope segment matched by any previous assertion
                # and trim that and everything preceding it.
                score = sublime.score_selector(scope, scope_above)
                if score > 0:
                    scope_parts = scope.split(' ')
                    matched_count = -(-score.bit_length() // 3) - 1

                    score_of_last_part = score >> matched_count * 3
                    possible_score_of_last_part = len(scope_parts[matched_count - 1].split('.'))
                    if score_of_last_part != possible_score_of_last_part:
                        matched_count -= 1

                    scope = ' '.join(scope_parts[matched_count:])

        # delete the existing selection
        if not view.sel()[0].empty():
            view.erase(edit, view.sel()[0])

        view.insert(edit, insert_at, (character * max(1, length)) + ' ' + scope + end_token)

        # move the selection to cover the added scope name,
        # so that the user can easily insert another ^ to extend the test
        view.sel().clear()
        view.sel().add(sublime.Region(
            insert_at + length,
            insert_at + length + len(' ' + scope + end_token)
        ))
Exemplo n.º 21
0
 def stop_or_extend_note(self, note):
     self.active_notes[note] -= 1
     if self.active_notes[note] <= 0:
         del self.active_notes[note]
         listener = sublime_plugin.find_view_event_listener(self.view, Piano)
         listener.note_off(*note)
Exemplo n.º 22
0
 def on_post_save(self, view):
     listener = sublime_plugin.find_view_event_listener(
         view, SettingsListener)
     if listener and listener.known_settings:
         listener.known_settings.trigger_settings_reload()
Exemplo n.º 23
0
 def is_enabled(self):
     return sublime_plugin.find_view_event_listener(self.view, Piano) is not None