Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is this possibly useful? #144

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 92 additions & 56 deletions terminus/mouse.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import sublime
import sublime_plugin

import re
# -*- coding: utf-8 -*-
import logging
import re
import webbrowser
from pathlib import Path

from .terminal import Terminal, CONTINUATION
import sublime
import sublime_plugin

from .terminal import CONTINUATION, Terminal
from .utils import highlight_key

logger = logging.getLogger('Terminus')

rex = re.compile(
r'''(?x)
rex = re.compile(r'''(?x)
\b(?:
https?://(?:(?:[a-zA-Z0-9\-_]+(?:\.[a-zA-Z0-9\-._]+)+)|localhost)| # http://
www\.[a-zA-Z0-9\-_]+(?:\.[a-zA-Z0-9\-._]+)+ # www.
)
/?[a-zA-Z0-9\-._?,!'(){}\[\]/+&@%$#=:"|~;]* # url path and query string
[a-zA-Z0-9\-_~:/#@$*+=] # allowed end chars
''')
rexf = re.compile(
r'(?i)(?P<file>(([a-zA-Z]:)|((\\||\.\.?|/){1,2}\w+)\$?|\w+)((\\|/)(\w[\w]*.*))\.([a-zA-Z0-9]+))([\",\s]+)?((line\s)|\(|$|:)(?P<line>\d+)?(\)|$|\D)'
)
rexf_local = re.compile(
r'(?i)(?:(?<=\"))(?P<file>[a-zA-Z0-9\-_\./\\]+)(?:(?=\"))(?:\",)?(?:\sline\s)(?P<line>[0-9]+)'
)

URL_POPUP = """
<style>
Expand All @@ -41,7 +48,7 @@
"""


def find_url(view, event=None, pt=None):
def find_common(view, event=None, pt=None):
if event:
pt = view.window_to_text((event["x"], event["y"]))
line = view.line(pt)
Expand All @@ -50,33 +57,58 @@ def find_url(view, event=None, pt=None):
line.b = pt + 1024

text = view.substr(line)
original_text = text
text = text.replace(CONTINUATION + "\n", "")
it = rex.finditer(text)

for match in it:
if match.start() <= (pt - line.a) and match.end() >= (pt - line.a):
url = text[match.start():match.end()]
if url[0:3] == "www":
return "http://" + url
else:
return url

return None


def find_url_region(view, event=None, pt=None):
if event:
pt = view.window_to_text((event["x"], event["y"]))
line = view.line(pt)
return text, line, pt, original_text

line.a = max(line.a, pt - 1024)
line.b = pt + 1024

text = view.substr(line)
original_text = text
text = text.replace(CONTINUATION + "\n", "")
def find_url(view, event=None, pt=None, *args):
def on_navigate(action):
if action == "open":
webbrowser.open_new_tab(url)

text, line, pt, _ = args
for match in rex.finditer(text):
if match.start() <= (pt - line.a) and match.end() >= (pt - line.a):
url = text[match.start():match.end()]
if url[0:3] == "www":
url = "http://" + url
return url, rex, on_navigate
return None, None, None


def find_file(view, event=None, pt=None, *args):
def on_navigate(action):
if action == "open":
view.window().open_file(full_path, sublime.ENCODED_POSITION)

text, line, pt, _ = args
found = False
for regexp in (rexf, rexf_local):
for m in regexp.finditer(text):
if m.start() <= (pt - line.a) and m.end() >= (pt - line.a):
found = True
break
if found:
path, line = m.group('file'), m.group('line')
full_path = path = Path(path)
is_abs = path.is_absolute() and full_path.exists()
if not is_abs:
for folder in view.window().folders():
full_path = Path(folder).joinpath(path)
if full_path.exists():
is_abs = True
break
if is_abs:
if line:
full_path = ':'.join((str(full_path), line))
return full_path, regexp, on_navigate
return None, None, None


def find_region(view, event=None, pt=None, reg=None):
text, line, pt, original_text = find_common(view, event, pt)
for match in reg.finditer(text):
if match.start() <= (pt - line.a) and match.end() >= (pt - line.a):
a = match.start()
b = match.end()
Expand All @@ -87,8 +119,16 @@ def find_url_region(view, event=None, pt=None):
return None


class TerminusMouseEventListener(sublime_plugin.EventListener):
def find_something(view, event=None, pt=None):
args = find_common(view, event, pt)
for func in (find_url, find_file):
thing, regexp, on_nav = func(view, event, pt, *args)
if thing:
return thing, regexp, on_nav
return None, None, None


class TerminusMouseEventListener(sublime_plugin.EventListener):
def on_text_command(self, view, command_name, args):
terminal = Terminal.from_id(view.id())
if not terminal:
Expand All @@ -103,62 +143,58 @@ def on_hover(self, view, point, hover_zone):
return
if hover_zone != sublime.HOVER_TEXT:
return
url = find_url(view, pt=point)
for_open, for_region, on_nav = find_something(view, pt=point)

if not url:
if not for_open:
return

def on_navigate(action):
if action == "open":
webbrowser.open_new_tab(url)

def on_hide():
if link_key:
view.erase_regions(link_key)

url_region = find_url_region(view, pt=point)
url_region = find_region(view, pt=point, reg=for_region)

link_key = None
if url_region:
link_key = highlight_key(view)
view.add_regions(
link_key,
[sublime.Region(*url_region)],
"meta",
flags=sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SOLID_UNDERLINE)
view.add_regions(link_key, [sublime.Region(*url_region)],
"meta",
flags=sublime.DRAW_NO_FILL
| sublime.DRAW_NO_OUTLINE
| sublime.DRAW_SOLID_UNDERLINE)

view.show_popup(
URL_POPUP,
sublime.HIDE_ON_MOUSE_MOVE_AWAY,
location=point,
on_navigate=on_navigate, on_hide=on_hide)
view.show_popup(URL_POPUP,
sublime.HIDE_ON_MOUSE_MOVE_AWAY,
location=point,
on_navigate=on_nav,
on_hide=on_hide)


class TerminusOpenContextUrlCommand(sublime_plugin.TextCommand):
def run(self, edit, event):
url = find_url(self.view, event)
webbrowser.open_new_tab(url)
func = find_something(self.view, event)[-1]
func('open')

def is_enable(self, *args, **kwargs):
terminal = Terminal.from_id(self.view.id())
return terminal is not None

def is_visible(self, event):
terminal = Terminal.from_id(self.view.id())
return terminal is not None and find_url(self.view, event) is not None
return terminal is not None and find_something(self.view, event)[0] is not None

def description(self, event):
url = find_url(self.view, event)
if len(url) > 64:
url = url[0:64] + "..."
return "Open " + url
for_open = find_something(self.view, event)[0]
if len(for_open) > 64:
for_open = for_open[0:64] + "..."
return "Open " + for_open

def want_event(self):
return True


class TerminusClickCommand(sublime_plugin.TextCommand):
"""Reset cursor position if the click is occured below the last row."""

def run_(self, edit, args):
view = self.view
window = view.window()
Expand Down