class WebJumpPrompt(Prompt): label = "url/webjump:" complete_options = {"match": Prompt.SimpleMatch} history = PromptHistory() force_new_buffer = False keymap = WEBJUMP_PROMPT_KEYMAP def completer_model(self): data = [] for name, w in WEBJUMPS.items(): data.append((name, w.doc)) for url, name in self.bookmarks: data.append((name, url)) return PromptTableModel(data) def enable(self, minibuffer): self.bookmarks = app().bookmarks().list() Prompt.enable(self, minibuffer) self.new_buffer = PromptNewBuffer(self.ctx, self.force_new_buffer) self.new_buffer.enable(minibuffer) minibuffer.input().textEdited.connect(self._text_edited) minibuffer.input().installEventFilter(self) self._wc_model = QStringListModel() self._wb_model = minibuffer.input().completer_model() self._active_webjump = None self._completer = None self._popup_sel_model = None def eventFilter(self, obj, event): # call _text_edited on backspace release, as this is not reported by # the textEdited slot. if event.type() == QEvent.KeyRelease: if event.key() == Qt.Key_Backspace: self._text_edited(self.minibuffer.input().text()) return Prompt.eventFilter(self, obj, event) def _set_active_webjump(self, wj): if self._active_webjump == wj: return if self._active_webjump: if self._completer: self._completer.completed.disconnect(self._got_completions) self._completer.abort() self._completer.deleteLater() self._completer = None m_input = self.minibuffer.input() if wj: self._completer = wj.complete_fn() self._completer.completed.connect(self._got_completions) # set matching strategy m_input.set_match(None) model = self._wc_model else: m_input.set_match(Prompt.SimpleMatch) model = self._wb_model self._active_webjump = wj if m_input.completer_model() != model: m_input.popup().hide() m_input.set_completer_model(model) if self._popup_sel_model: self._popup_sel_model.selectionChanged.disconnect( self._popup_selection_changed) self._popup_sel_model = None if wj: m_input.popup().selectionModel()\ .selectionChanged.connect( self._popup_selection_changed ) def _popup_selection_changed(self, _sel, _desel): # try to abort any completion if the user select something in # the popup if self._completer: self._completer.abort() def _text_edited(self, text): # search for a matching webjump first_word = text.split(" ")[0].split("://")[0] if first_word in [w for w in WEBJUMPS if len(w) < len(text)]: self._set_active_webjump(WEBJUMPS[first_word]) self.start_completion(self._active_webjump) else: # didn't find a webjump, go back to matching # webjump/bookmark/history self._set_active_webjump(None) def start_completion(self, webjump): text = self.minibuffer.input().text() prefix = webjump.name + ("://" if webjump.protocol else " ") self._completer.abort() self._completer.complete(text[len(prefix):]) @Slot(list) def _got_completions(self, data): if self._active_webjump: self._wc_model.setStringList(data) text = self.minibuffer.input().text() prefix = self._active_webjump.name + \ ("://" if self._active_webjump.protocol else " ") self.minibuffer.input().show_completions(text[len(prefix):]) def close(self): Prompt.close(self) self.minibuffer.input().removeEventFilter(self) # not sure if those are required; self._wb_model.deleteLater() self._wc_model.deleteLater() def get_buffer(self): return self.new_buffer.get_buffer() def _on_completion_activated(self, index): super()._on_completion_activated(index) chosen_text = self.minibuffer.input().text() # if there is already an active webjump, if self._active_webjump: # add the selected completion after it if self._active_webjump.protocol: self.minibuffer.input().setText(self._active_webjump.name + "://" + chosen_text) else: self.minibuffer.input().setText(self._active_webjump.name + " " + chosen_text) # if we just chose a webjump # and not WEBJUMPS[chosen_text].protocol: elif chosen_text in WEBJUMPS: # add a space after the selection self.minibuffer.input().setText(chosen_text + ( " " if not WEBJUMPS[chosen_text].protocol else "://"))
class WebJumpPrompt(Prompt): label = "url/webjump:" complete_options = {"match": Prompt.SimpleMatch} history = PromptHistory() keymap = WEBJUMP_KEYMAP default_input = "alternate" def completer_model(self): data = [] for name, w in WEBJUMPS.items(): data.append((name, w.doc)) for url, name in self.bookmarks: data.append((name, url)) return PromptTableModel(data) def enable(self, minibuffer): self.bookmarks = app().bookmarks().list() Prompt.enable(self, minibuffer) minibuffer.input().textEdited.connect(self._text_edited) minibuffer.input().installEventFilter(self) self._wc_model = QStringListModel() self._wb_model = minibuffer.input().completer_model() self._active_webjump = None self._completer = None self._popup_sel_model = None input = minibuffer.input() if self.default_input in ("current_url", "alternate"): url = current_buffer().url().toString() input.setText(url) input.setSelection(0, len(url)) if self.default_input == "alternate": input.deselect() elif self.default_input == "default_webjump": wj = WEBJUMPS.get(webjump_default.value) if wj: input.setText(wj.name + ("://" if wj.protocol else " ")) def eventFilter(self, obj, event): # call _text_edited on backspace release, as this is not reported by # the textEdited slot. if event.type() == QEvent.KeyRelease: if event.key() == Qt.Key_Backspace: self._text_edited(self.minibuffer.input().text()) return Prompt.eventFilter(self, obj, event) def _set_active_webjump(self, wj): if self._active_webjump == wj: return if self._active_webjump: if self._completer: self._completer.completed.disconnect(self._got_completions) self._completer.abort() self._completer.deleteLater() self._completer = None m_input = self.minibuffer.input() if wj: self._completer = wj.complete_fn() self._completer.completed.connect(self._got_completions) # set matching strategy m_input.set_match(None) model = self._wc_model else: m_input.set_match(Prompt.SimpleMatch) model = self._wb_model self._active_webjump = wj if m_input.completer_model() != model: m_input.popup().hide() m_input.set_completer_model(model) if self._popup_sel_model: self._popup_sel_model.selectionChanged.disconnect( self._popup_selection_changed) self._popup_sel_model = None if wj: m_input.popup().selectionModel()\ .selectionChanged.connect( self._popup_selection_changed ) def _popup_selection_changed(self, _sel, _desel): # try to abort any completion if the user select something in # the popup if self._completer: self._completer.abort() def _text_edited(self, text): # search for a matching webjump first_word = text.split(" ")[0].split("://")[0] if first_word in [w for w in WEBJUMPS if len(w) < len(text)]: self._set_active_webjump(WEBJUMPS[first_word]) self.start_completion(self._active_webjump) else: # didn't find a webjump, go back to matching # webjump/bookmark/history self._set_active_webjump(None) def start_completion(self, webjump): text = self.minibuffer.input().text() prefix = webjump.name + ("://" if webjump.protocol else " ") self._completer.abort() self._completer.complete(text[len(prefix):]) @Slot(list) def _got_completions(self, data): if self._active_webjump: self._wc_model.setStringList(data) text = self.minibuffer.input().text() prefix = self._active_webjump.name + \ ("://" if self._active_webjump.protocol else " ") self.minibuffer.input().show_completions(text[len(prefix):]) def close(self): Prompt.close(self) self.minibuffer.input().removeEventFilter(self) # not sure if those are required; self._wb_model.deleteLater() self._wc_model.deleteLater() def _on_completion_activated(self, index): super()._on_completion_activated(index) chosen_text = self.minibuffer.input().text() # if there is already an active webjump, if self._active_webjump: # add the selected completion after it if self._active_webjump.protocol: self.minibuffer.input().setText(self._active_webjump.name + "://" + chosen_text) else: self.minibuffer.input().setText(self._active_webjump.name + " " + chosen_text) # if we just chose a webjump # and not WEBJUMPS[chosen_text].protocol: elif chosen_text in WEBJUMPS: # add a space after the selection self.minibuffer.input().setText(chosen_text + ( " " if not WEBJUMPS[chosen_text].protocol else "://")) def value(self): value = super().value() if value is None: return # split webjumps and protocols between command and argument if re.match(r"^\S+://.*", value): args = value.split("://", 1) else: args = value.split(" ", 1) command = args[0] # Look for webjumps webjump = None if command in WEBJUMPS: webjump = WEBJUMPS[command] else: # Look for a incomplete webjump, accepting a candidate # if there is a single option candidates = [wj for wj in WEBJUMPS if wj.startswith(command)] if len(candidates) == 1: webjump = WEBJUMPS[candidates[0]] if webjump: if not webjump.allow_args: # send the url as is return webjump.url elif len(args) < 2: # send the url without a search string return webjump.url.replace("%s", "") else: # format the url as entered if webjump.protocol: return value else: return webjump.url.replace( "%s", str(QUrl.toPercentEncoding(args[1]), "utf-8")) # Look for a bookmark bookmarks = {name: url for url, name in self.bookmarks} if value in bookmarks: return bookmarks[value] # Look for a incomplete bookmarks, accepting a candidate # if there is a single option candidates = [bm for bm in bookmarks if bm.startswith(command)] if len(candidates) == 1: return bookmarks[candidates[0]] # No webjump, no bookmark, look for a url if "://" not in value: url = QUrl.fromUserInput(value) if url.isValid(): # default scheme is https for us if url.scheme() == "http": url.setScheme("https") return url return value
class WebJumpPrompt(Prompt): label = "url/webjump:" complete_options = { "autocomplete": True, } history = PromptHistory() ask_completions = Signal(object, str, str) force_new_buffer = False def completer_model(self): data = [] for name, w in WEBJUMPS.items(): if w.allow_args: name = name data.append((name, w.doc)) return PromptTableModel(data) def enable(self, minibuffer): Prompt.enable(self, minibuffer) self.new_buffer = PromptNewBuffer(self.force_new_buffer) self.new_buffer.enable(minibuffer) minibuffer.input().textEdited.connect(self._text_edited) self._wc_model = QStringListModel() self._wb_model = minibuffer.input().completer_model() self._cthread = QThread(app()) self._creceiver = CompletionReceiver() self._creceiver.moveToThread(self._cthread) self._completion_timer = 0 self._active_webjump = None self._cthread.finished.connect(self._cthread.deleteLater) self.ask_completions.connect(self._creceiver.get_completions) self._creceiver.got_completions.connect(self._got_completions) self._cthread.start() def _text_edited(self, text): model = self._wb_model for name, w in WEBJUMPS.items(): if w.allow_args and w.complete_fn: name = name if text.startswith(name): model = self._wc_model self._active_webjump = (w, name) if self._completion_timer != 0: self.killTimer(self._completion_timer) self._completion_timer = self.startTimer(10) break if self.minibuffer.input().completer_model() != model: self.minibuffer.input().popup().hide() self.minibuffer.input().set_completer_model(model) def timerEvent(self, _): text = self.minibuffer.input().text() w, name = self._active_webjump self.ask_completions.emit(w, name, text[len(name):]) self.killTimer(self._completion_timer) self._completion_timer = 0 @Slot(list) def _got_completions(self, data): self._wc_model.setStringList(data) self.minibuffer.input().show_completions() def close(self): Prompt.close(self) self._cthread.quit() # not sure if those are required; self._wb_model.deleteLater() self._wc_model.deleteLater() def get_buffer(self): return self.new_buffer.get_buffer()