Skip to content

Commit

Permalink
Merge pull request #9 from SPBSTU-OrangeTeam/feature/comments
Browse files Browse the repository at this point in the history
Feature/comments
  • Loading branch information
mandarin1029 committed Dec 22, 2020
2 parents dd94446 + 302f429 commit 2eac26b
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 86 deletions.
2 changes: 1 addition & 1 deletion Default.sublime-commands
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[
{ "caption": "Quip: Show File Tree", "command": "show_file_tree"},
{ "caption": "QuipTest: Show Contacts", "command": "show_test_contacts"}
{ "caption": "Quip: Show Contacts", "command": "show_contacts"}
]
4 changes: 1 addition & 3 deletions Default.sublime-keymap
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
[

{ "keys": ["alt+a"], "command": "send_chat_message"},
{ "keys": ["alt+d"], "command": "open_chat"}
{ "keys": ["alt+a"], "command": "send_chat_message"}
]
188 changes: 120 additions & 68 deletions QuipEditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
import os
from sublime import Region
from .src.providers import QuipProvider
from .src.managers import TabsManager, TREE_VIEW_TAB_ID
from .src.managers import TREE_VIEW_TAB_ID, TabsManager, ChatView
from .src.deps.markdownify import markdownify as md


COMMAND_OPEN_DOCUMENT = "open_document"
COMMAND_OPEN_CHAT = "open_chat"
COMMAND_PRINT_QUIP_FILE_TREE = "print_quip_file_tree"
COMMAND_GET_SELECTED_DOCUMENT = "insert_selected_document"
COMMAND_INSERT_SELECTED_DOCUMENT = "insert_selected_document"
COMMAND_INSERT_CHAT_MESSAGES = 'insert_chat_messages'
COMMAND_INSERT_CONTACTS = 'insert_contacts'

KEY_THREAD_ID = "thread_id"
KEY_FILE_TREE_PHANTOM_SET = "file_tree_phantom_set"
KEY_CONTACTS_PHANTOM_SET = "contacts_phantom_set"
KEY_MESSAGES_PHANTOM_SET = "messages_phantom_set"


def plugin_loaded():
Expand All @@ -26,18 +30,20 @@ def plugin_loaded():


class OpenDocumentCommand(sublime_plugin.WindowCommand):
def run(self, thread_id):

def run(self, thread_id, markdown=True):
view = manager.get_tab(thread_id)
if not view:
view = self.window.new_file()
self.window.focus_view(view)
view.retarget(CACHE_DIRECTORY + "/" + thread_id + ".html")
view.run_command(COMMAND_GET_SELECTED_DOCUMENT, {"thread_id": thread_id})
view.run_command(COMMAND_INSERT_SELECTED_DOCUMENT, {"thread_id": thread_id, 'markdown': markdown})
view.run_command('save')
manager.add(thread_id, view)


class ShowFileTreeCommand(sublime_plugin.WindowCommand):

def run(self):
view = manager.get_thread(TREE_VIEW_TAB_ID)
if not view:
Expand All @@ -48,11 +54,20 @@ def run(self):


class InsertSelectedDocumentCommand(sublime_plugin.TextCommand):
def run(self, edit, thread_id):
self.view.replace(edit, Region(0, self.view.size()), md(quip.get_document_content(thread_id)))

def run(self, edit, thread_id, markdown):
html = quip.get_document_content(thread_id)
self.view.replace(edit, Region(0, self.view.size()), html) #md(html) if markdown else html)
manager.comments[thread_id] = quip.get_comments(thread_id)
self.view.window().run_command(
COMMAND_OPEN_CHAT,
{"thread": thread_id,
'name': 'Comments'}
)


class PrintQuipFileTree(sublime_plugin.TextCommand):

def run(self, edit):
self.view.erase_phantoms(KEY_FILE_TREE_PHANTOM_SET)
self.view.set_read_only(True)
Expand Down Expand Up @@ -90,68 +105,111 @@ def _print_tree(self, node, prefix, postfix):
return str_result


class ShowContactsCommand(sublime_plugin.WindowCommand):

def run(self):
view = self.window.new_file()
view.run_command(COMMAND_INSERT_CONTACTS)


class InsertContactsCommand(sublime_plugin.TextCommand):

def run(self, edit):
self.view.erase_phantoms(KEY_CONTACTS_PHANTOM_SET)
self.view.set_read_only(True)
self.view.set_name("Contacts")

user, friends = quip.get_contacts()
tree = str(user) if friends else "Нет контактов"
tree += "<ul>"
tree += '\n'.join(["<li>%s</li>" % str(friend) for friend in friends if friend])
tree += "</ul>"

phantom = sublime.Phantom(
region=Region(0, self.view.size()),
content=tree,
layout=sublime.LAYOUT_INLINE,
on_navigate=lambda thread: self.view.window().run_command(
COMMAND_OPEN_CHAT,
{"thread": thread}
)
)
sublime.PhantomSet(self.view, KEY_CONTACTS_PHANTOM_SET).update([phantom, phantom])


class OpenChatCommand(sublime_plugin.WindowCommand):

def __init__(self, window):
super().__init__(window)

def run(self):
if hasattr(self, 'toggled') and self.toggled:
return self._close_chat()
self._open_chat()
def run(self, thread=None, name='Private Chat'):
self._close_chat()
self._open_chat(thread, name)

def _open_chat(self):
def _open_chat(self, thread, name):
if not thread:
return
self.window.run_command('set_layout', {
"cols": [0, 0.70, 1.0],
"cols": [0, 1.0],
"rows": [0.0, 1.0],
"cells": [[0, 0, 1, 1], [1, 0, 2, 1]]
"cells": [[0, 0, 1, 1]]
})
self._load_recent_chat() # TODO: Open selected chat
self.toggled = True
self.chat = sublime.active_window().new_file()
manager.set_chat(self.chat_id, self.chat)
self.chat.run_command(COMMAND_INSERT_CHAT_MESSAGES,
{"messages": [str(m) for m in quip.get_messages(self.chat_id)]})
self.chat.set_name(self.chat_name)

def _close_chat(self):
self.window.run_command('set_layout', {
"cols": [0, 1.0],
"cols": [0, 0.60, 1.0],
"rows": [0.0, 1.0],
"cells": [[0, 0, 1, 1]]
"cells": [[0, 0, 1, 1], [1, 0, 2, 1]]
})
self.toggled = False
self.window.focus_view(self.chat)
if self.window.active_view() == self.chat:
self.window.run_command('close')
manager.reset_chat()
chat = ChatView(thread, sublime.active_window().new_file(), name)
manager.set_chat(chat)
manager.chat.view.run_command(
COMMAND_INSERT_CHAT_MESSAGES,
{"messages": [str(m) for m in quip.get_messages(thread)]}
)

def _load_recent_chat(self):
chats = quip.get_recent_chats()
self.chat_id, self.chat_name = chats.pop()
def _close_chat(self):
if not manager.chat or not manager.chat.view:
return
self.window.focus_view(manager.chat.view)
if self.window.active_view() == manager.chat.view:
self.window.run_command('close')


class InsertChatMessagesCommand(sublime_plugin.TextCommand):

def run(self, edit, messages):
result = '\n'.join(messages)
manager.chat.set_scratch(False)
manager.chat.set_read_only(False)
self.view.insert(edit, self.view.size(), result)
manager.chat.set_read_only(True)
manager.chat.set_scratch(True)
self.view.erase_phantoms(KEY_MESSAGES_PHANTOM_SET)

result = ''.join([self._convert_to_html(m) for m in messages])
manager.chat.view.set_scratch(False)
manager.chat.view.set_read_only(False)

phantom = sublime.Phantom(
region=Region(0, self.view.size()),
content=result,
layout=sublime.LAYOUT_INLINE
)
manager.chat.add_phantom(phantom)
sublime.PhantomSet(self.view, KEY_MESSAGES_PHANTOM_SET).update(manager.chat.phantoms)

manager.chat.view.set_read_only(True)
manager.chat.view.set_scratch(True)

def _convert_to_html(self, message):
return "<div>%s</div>" % message


class SendChatMessageCommand(sublime_plugin.TextCommand):

def run(self, edit):
current_window = sublime.active_window()
if manager.chat:
if manager.chat and manager.chat.view:
current_window.show_input_panel('Enter chat message:', '', self._send_message, None, None)

def _send_message(self, text: str):
message = quip.send_message(manager.chat_id, text)
manager.chat.run_command(COMMAND_INSERT_CHAT_MESSAGES, {"messages": [str(message)]})
if not manager.chat or not manager.chat.id:
return
message = quip.send_message(manager.chat.id, text)
manager.chat.view.run_command(COMMAND_INSERT_CHAT_MESSAGES, {"messages": [str(message)]})


class UploadChangesOnSave(sublime_plugin.EventListener):
Expand All @@ -167,34 +225,28 @@ def on_pre_save(self, view):

quip.edit_document(thread_id=manager.get_thread(view), content=html)

def on_pre_close(self, view):
def on_close(self, view):
if manager.chat and manager.chat.view == view:
sublime.active_window().run_command('set_layout', {
"cols": [0, 1.0],
"rows": [0.0, 1.0],
"cells": [[0, 0, 1, 1]]
})
manager.reset_chat()
manager.remove_tab(view=view)


# Section with test commands!
class ShowTestContactsCommand(sublime_plugin.WindowCommand):
def run(self, **args):
view = self.window.new_file()
view.run_command("insert_test_contacts")


class InsertTestContactsCommand(sublime_plugin.TextCommand):
class ShowCommentsOnHover(sublime_plugin.EventListener):

def run(self, edit):
user, friends = quip.get_contacts()
tree = self._print_user(user)
tree += "<ul>"
for friend in friends:
tree += "<li>%s</li>" % self._print_user(friend)
tree += "</ul>"
phantom = sublime.Phantom(
region=Region(0, self.view.size()),
content=tree,
layout=sublime.LAYOUT_INLINE
)
sublime.PhantomSet(self.view, "chat_phantom_set").update([phantom, phantom])

def _print_user(self, user):
if user is None:
return "<div> Нет контактов </div>"
return "<div>%s<span>%s</span></div>" % (user.avatar, user.name)
def on_hover(self, view, point, hover_zone):
thread = manager.get_thread(view)
messages = manager.comments.get(thread)
if not messages or view.is_popup_visible():
return
word_region = view.word(point)
word = view.substr(word_region)
comments = [str(comment) for comment in messages if word in comment.sections]
view.sel().clear()
view.sel().add(Region(point))
view.show_popup_menu(comments, None)
#view.show_popup('\n'.join(comments), flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY, location=point)
20 changes: 14 additions & 6 deletions src/entities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@

class Message:

def __init__(self, text, author_id, author_name, created_at, updated_at):
def __init__(self, text, author_id, author_name, created_at, updated_at, sections=None):
self.text = text
self.author_id = author_id
self.author_name = author_name

self.edited = updated_at - created_at >= 10**6 # If difference more than 1 second
self.timestamp = datetime.fromtimestamp(max(updated_at, created_at)/(10**6))
self.sections = sections or []


def __str__(self):
return "%s | %s [%s] %s: %s" % (self.author_id, self.author_name,
self.timestamp, "(edited)" if self.edited else "", self.text)
return "[%s] %s: %s%s" % (self.timestamp.strftime('%d.%m %H:%M'), self.author_name,
self.text, " (edited)" if self.edited else "")


class TreeNode:
Expand All @@ -27,8 +28,15 @@ def __init__(self, name, thread_type, thread_id, children=None):

class User:

def __init__(self, user_id, name, chat_thread_id = None):
def __init__(self, user_id, name, thread=None):
self.avatar = Random(user_id).choice([' 😎 ', ' 🥺 ', ' 😃 ', ' 🐻 ', ' 🙊 '])
self.id = user_id
self.name = name
self.chat_thread_id = chat_thread_id
self.thread = thread

def __str__(self):
return "<div>{0} <span><a href=\'{1}\' title=\'Test hint\'>{2}</a></span></div>".format(
self.avatar,
self.thread,
self.name
)
29 changes: 21 additions & 8 deletions src/managers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
TREE_VIEW_TAB_ID = "TREE_VIEW_TAB_ID"


class ChatView:

def __init__(self, id=None, view=None, name="Private Chat"):
self.id = id
self.view = view
self.name = name
self.phantoms = []

if self.view and self.name:
self.view.set_name(name)

def add_phantom(self, phantom):
self.phantoms.extend([phantom, phantom])


class TabsManager:

def __init__(self):
self._tabs = dict()
self.chat = None
self.chat_id = None
self.chat = ChatView()
self.comments = dict()

def add(self, thread: int, view):
self._tabs[thread] = view
Expand All @@ -23,15 +38,13 @@ def get_tab(self, thread_id):
def contains(self, view):
return view in self._tabs.values()

def set_chat(self, thread_id, view):
self.chat = view
self.chat_id = thread_id
def set_chat(self, chat):
self.chat = chat

def reset_chat(self):
if self.chat_id:
self.remove_tab(thread=self.chat_id)
if self.chat and self.chat.id:
self.remove_tab(thread=self.chat.id)
self.chat = None
self.chat_id = None

def remove_tab(self, thread=None, view=None):
""" You must provide one parameter, though both is fine too """
Expand Down
14 changes: 14 additions & 0 deletions src/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ def get_contacts(self):
]
return user, friends

def get_comments(self, thread_id):
messages = self._quip.get_messages(thread_id)
comments = [
Message(
comment.get("text"), comment.get("author_id"), comment.get("author_name"),
comment.get("created_usec"), comment.get("updated_usec"),
comment.get('annotation').get('highlight_section_ids')
)
for comment in messages
if comment.get('annotation')
]
comments.reverse()
return comments

def get_messages(self, thread_id):
messages = self._quip.get_messages(thread_id, count=100)
# For future if we get a troubles with order of messages
Expand Down

0 comments on commit 2eac26b

Please sign in to comment.