diff --git a/README.md b/README.md
index 03df752..2e851cb 100644
--- a/README.md
+++ b/README.md
@@ -103,24 +103,30 @@ You can use ctrl k (or your custom shortcut) to navigate in your DMs
You can use ctrl d (or your custom shortcut) to set snooze time.
+### Get permalink
+
+Focus on message and press r (or your custom shortcut) to get permalink (Quote message) and it will be put into your chat box.
+
### Default keybindings
```json
{
- "keymap": {
- "cursor_down": "j",
- "cursor_left": "h",
- "cursor_right":"l",
- "cursor_up": "k",
- "delete_message": "d",
- "edit_message": "e",
- "go_to_chatbox": "c",
- "go_to_profile": "p",
- "go_to_sidebar": "esc",
- "open_quick_switcher": "ctrl k",
- "quit_application": "q",
- "set_edit_topic_mode": "t",
- "set_insert_mode": "i",
- "yank_message": "y"
+ "keymap": {
+ "cursor_down": "j",
+ "cursor_left": "h",
+ "cursor_right": "l",
+ "cursor_up": "k",
+ "delete_message": "d",
+ "edit_message": "e",
+ "go_to_chatbox": "c",
+ "go_to_profile": "p",
+ "go_to_sidebar": "esc",
+ "open_quick_switcher": "ctrl k",
+ "quit_application": "q",
+ "set_edit_topic_mode": "t",
+ "set_insert_mode": "i",
+ "yank_message": "y",
+ "get_permalink": "r",
+ "set_snooze": "ctrl d"
}
}
```
diff --git a/app.py b/app.py
index 494cbac..c655c1a 100755
--- a/app.py
+++ b/app.py
@@ -12,7 +12,8 @@
import urwid
from datetime import datetime
from sclack.components import Attachment, Channel, ChannelHeader, ChatBox, Dm
-from sclack.components import Indicators, MarkdownText, Message, MessageBox
+from sclack.components import Indicators, MarkdownText, MessageBox
+from sclack.component.message import Message
from sclack.components import NewMessagesDivider, Profile, ProfileSideBar
from sclack.components import Reaction, SideBar, TextDivider
from sclack.components import User, Workspaces
@@ -314,6 +315,16 @@ def edit_message(self, widget, user_id, ts, original_text):
self.chatbox.message_box.text = original_text
widget.set_edit_mode()
+ def get_permalink(self, widget, channel_id, ts):
+ try:
+ permalink = self.store.get_permalink(channel_id, ts)
+ if permalink and permalink.get('permalink'):
+ text = permalink.get('permalink')
+ self.set_insert_mode()
+ self.chatbox.message_box.text = text
+ except:
+ pass
+
def delete_message(self, widget, user_id, ts):
if self.store.state.auth['user_id'] == user_id:
if self.store.delete_message(self.store.state.channel['id'], ts)['ok']:
@@ -487,6 +498,7 @@ def render_message(self, message, channel_id=None):
self.lazy_load_images(files, message)
urwid.connect_signal(message, 'edit_message', self.edit_message)
+ urwid.connect_signal(message, 'get_permalink', self.get_permalink)
urwid.connect_signal(message, 'go_to_profile', self.go_to_profile)
urwid.connect_signal(message, 'go_to_sidebar', self.go_to_sidebar)
urwid.connect_signal(message, 'delete_message', self.delete_message)
diff --git a/config.json b/config.json
index 0ce592d..8f7c87a 100644
--- a/config.json
+++ b/config.json
@@ -16,6 +16,7 @@
"set_edit_topic_mode": "t",
"set_insert_mode": "i",
"yank_message": "y",
+ "get_permalink": "r",
"set_snooze": "ctrl d"
},
"sidebar": {
diff --git a/sclack/component/message.py b/sclack/component/message.py
new file mode 100644
index 0000000..1422dcd
--- /dev/null
+++ b/sclack/component/message.py
@@ -0,0 +1,116 @@
+import re
+
+import urwid
+import pyperclip
+import webbrowser
+from sclack.store import Store
+from sclack.component.time import Time
+
+
+class Message(urwid.AttrMap):
+ __metaclass__ = urwid.MetaSignals
+ signals = [
+ 'delete_message',
+ 'edit_message',
+ 'get_permalink',
+ 'go_to_profile',
+ 'go_to_sidebar',
+ 'quit_application',
+ 'set_insert_mode',
+ 'mark_read',
+ ]
+
+ def __init__(self, ts, channel_id, user, text, indicators, reactions=(), attachments=()):
+ self.ts = ts
+ self.channel_id = channel_id
+ self.user_id = user.id
+ self.markdown_text = text
+ self.original_text = text.original_text
+ self.text_widget = urwid.WidgetPlaceholder(text)
+ main_column = [urwid.Columns([('pack', user), self.text_widget])]
+ main_column.extend(attachments)
+ self._file_index = len(main_column)
+ if reactions:
+ main_column.append(urwid.Columns([
+ ('pack', reaction) for reaction in reactions
+ ]))
+ self.main_column = urwid.Pile(main_column)
+ columns = [
+ ('fixed', 7, Time(ts)),
+ self.main_column,
+ ('fixed', indicators.size, indicators)
+ ]
+ self.contents = urwid.Columns(columns)
+ super(Message, self).__init__(self.contents, None, {
+ None: 'active_message',
+ 'message': 'active_message'
+ })
+
+ def keypress(self, size, key):
+ keymap = Store.instance.config['keymap']
+
+ if key == keymap['delete_message']:
+ urwid.emit_signal(self, 'delete_message', self, self.user_id, self.ts)
+ return True
+ elif key == keymap['edit_message']:
+ urwid.emit_signal(self, 'edit_message', self, self.user_id, self.ts, self.original_text)
+ return True
+ elif key == keymap['go_to_profile']:
+ urwid.emit_signal(self, 'go_to_profile', self.user_id)
+ return True
+ elif key == keymap['go_to_sidebar'] or key == keymap['cursor_left']:
+ urwid.emit_signal(self, 'go_to_sidebar')
+ return True
+ elif key == keymap['quit_application']:
+ urwid.emit_signal(self, 'quit_application')
+ return True
+ elif key == keymap['set_insert_mode']:
+ urwid.emit_signal(self, 'set_insert_mode')
+ return True
+ elif key == keymap['yank_message']:
+ try:
+ pyperclip.copy(self.original_text)
+ except pyperclip.PyperclipException:
+ pass
+ return True
+ elif key == keymap['get_permalink']:
+ # FIXME
+ urwid.emit_signal(self, 'get_permalink', self, self.channel_id, self.ts)
+ elif key == 'enter':
+ browser_name = Store.instance.config['features']['browser']
+
+ for item in self.markdown_text.markup:
+ type, value = item
+
+ if type == 'link' and re.compile(r'^https?://').search(value):
+ browser_instance = webbrowser if browser_name == '' else webbrowser.get(browser_name)
+ browser_instance.open(value, new=2)
+ break
+
+ return super(Message, self).keypress(size, key)
+
+ def set_text(self, text):
+ self.text_widget.original_widget = text
+
+ def set_edit_mode(self):
+ self.set_attr_map({
+ None: 'editing_message',
+ 'message': 'editing_message'
+ })
+
+ def unset_edit_mode(self):
+ self.set_attr_map({
+ None: None,
+ 'message': None
+ })
+
+ def selectable(self):
+ return True
+
+ @property
+ def file(self):
+ return None
+
+ @file.setter
+ def file(self, file):
+ self.main_column.contents.insert(self._file_index, (file, ('pack', 1)))
diff --git a/sclack/component/time.py b/sclack/component/time.py
new file mode 100644
index 0000000..70eed44
--- /dev/null
+++ b/sclack/component/time.py
@@ -0,0 +1,9 @@
+from datetime import datetime
+
+import urwid
+
+
+class Time(urwid.Text):
+ def __init__(self, timestamp):
+ time = datetime.fromtimestamp(float(timestamp)).strftime('%H:%M')
+ super(Time, self).__init__(('datetime', ' {} '.format(time)))
diff --git a/sclack/components.py b/sclack/components.py
index 8f6e461..9a2c369 100644
--- a/sclack/components.py
+++ b/sclack/components.py
@@ -517,110 +517,6 @@ def __init__(self, is_edited=False, is_starred=False):
super(Indicators, self).__init__(indicators)
-class Message(urwid.AttrMap):
- __metaclass__ = urwid.MetaSignals
- signals = [
- 'delete_message',
- 'edit_message',
- 'go_to_profile',
- 'go_to_sidebar',
- 'quit_application',
- 'set_insert_mode',
- 'mark_read',
- ]
-
- def __init__(self, ts, channel_id, user, text, indicators, reactions=(), attachments=()):
- self.ts = ts
- self.channel_id = channel_id
- self.user_id = user.id
- self.markdown_text = text
- self.original_text = text.original_text
- self.text_widget = urwid.WidgetPlaceholder(text)
- main_column = [urwid.Columns([('pack', user), self.text_widget])]
- main_column.extend(attachments)
- self._file_index = len(main_column)
- if reactions:
- main_column.append(urwid.Columns([
- ('pack', reaction) for reaction in reactions
- ]))
- self.main_column = urwid.Pile(main_column)
- columns = [
- ('fixed', 7, Time(ts)),
- self.main_column,
- ('fixed', indicators.size, indicators)
- ]
- self.contents = urwid.Columns(columns)
- super(Message, self).__init__(self.contents, None, {
- None: 'active_message',
- 'message': 'active_message'
- })
-
- def keypress(self, size, key):
- keymap = Store.instance.config['keymap']
-
- if key == keymap['delete_message']:
- urwid.emit_signal(self, 'delete_message', self, self.user_id, self.ts)
- return True
- elif key == keymap['edit_message']:
- urwid.emit_signal(self, 'edit_message', self, self.user_id, self.ts, self.original_text)
- return True
- elif key == keymap['go_to_profile']:
- urwid.emit_signal(self, 'go_to_profile', self.user_id)
- return True
- elif key == keymap['go_to_sidebar'] or key == keymap['cursor_left']:
- urwid.emit_signal(self, 'go_to_sidebar')
- return True
- elif key == keymap['quit_application']:
- urwid.emit_signal(self, 'quit_application')
- return True
- elif key == keymap['set_insert_mode']:
- urwid.emit_signal(self, 'set_insert_mode')
- return True
- elif key == keymap['yank_message']:
- try:
- pyperclip.copy(self.original_text)
- except pyperclip.PyperclipException:
- pass
- return True
- elif key == 'enter':
- browser_name = Store.instance.config['features']['browser']
-
- for item in self.markdown_text.markup:
- type, value = item
-
- if type == 'link' and re.compile(r'^https?://').search(value):
- browser_instance = webbrowser if browser_name == '' else webbrowser.get(browser_name)
- browser_instance.open(value, new=2)
- break
-
- return super(Message, self).keypress(size, key)
-
- def set_text(self, text):
- self.text_widget.original_widget = text
-
- def set_edit_mode(self):
- self.set_attr_map({
- None: 'editing_message',
- 'message': 'editing_message'
- })
-
- def unset_edit_mode(self):
- self.set_attr_map({
- None: None,
- 'message': None
- })
-
- def selectable(self):
- return True
-
- @property
- def file(self):
- return None
-
- @file.setter
- def file(self, file):
- self.main_column.contents.insert(self._file_index, (file, ('pack', 1)))
-
class MessageBox(urwid.AttrMap):
def __init__(self, user, typing=None, is_read_only=False):
self.read_only_widget = urwid.Text('You have no power here!', align='center')
@@ -971,12 +867,6 @@ def __init__(self, text='', align='left', char='─'):
]
super(TextDivider, self).__init__(body)
-
-class Time(urwid.Text):
- def __init__(self, timestamp):
- time = datetime.fromtimestamp(float(timestamp)).strftime('%H:%M')
- super(Time, self).__init__(('datetime', ' {} '.format(time)))
-
def shorten_hex(color):
if color.startswith('#'):
color = color[1:]
diff --git a/sclack/quick_switcher.py b/sclack/quick_switcher.py
index 0c0a563..2af09df 100644
--- a/sclack/quick_switcher.py
+++ b/sclack/quick_switcher.py
@@ -2,10 +2,7 @@
import time
import unicodedata
from .store import Store
-
-
-def get_icon(name):
- return Store.instance.config['icons'][name]
+from sclack.components import get_icon
def remove_diacritic(input):
diff --git a/sclack/store.py b/sclack/store.py
index 77f688a..eec697f 100644
--- a/sclack/store.py
+++ b/sclack/store.py
@@ -129,6 +129,10 @@ def mark_read(self, channel_id, ts):
elif self.is_dm(channel_id):
return self.slack.api_call('im.mark', channel=channel_id, ts=ts)
+ def get_permalink(self, channel_id, ts):
+ # https://api.slack.com/methods/chat.getPermalink
+ return self.slack.api_call('chat.getPermalink', channel=channel_id, message_ts=ts)
+
def set_snooze(self, snoozed_time):
return self.slack.api_call('dnd.setSnooze', num_minutes=snoozed_time)
diff --git a/sclack/widgets/set_snooze.py b/sclack/widgets/set_snooze.py
index d089d33..abb9817 100644
--- a/sclack/widgets/set_snooze.py
+++ b/sclack/widgets/set_snooze.py
@@ -1,9 +1,5 @@
import urwid
-from sclack.store import Store
-
-
-def get_icon(name):
- return Store.instance.config['icons'][name]
+from sclack.components import get_icon
class SetSnoozeWidgetItem(urwid.AttrMap):