[polari/wip/fmuellner/combined-gsoc: 24/103] Implement ResultView
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [polari/wip/fmuellner/combined-gsoc: 24/103] Implement ResultView
- Date: Fri, 22 Jul 2016 13:35:59 +0000 (UTC)
commit abb6c763e5c8c349f504c3a8de8197906cafa33a
Author: Kunaal Jain <kunaalus gmail com>
Date: Sat Jul 9 17:10:48 2016 +0530
Implement ResultView
src/resultView.js | 677 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 677 insertions(+), 0 deletions(-)
---
diff --git a/src/resultView.js b/src/resultView.js
index 846496b..e79ec7b 100644
--- a/src/resultView.js
+++ b/src/resultView.js
@@ -16,7 +16,28 @@ const PasteManager = imports.pasteManager;
const Signals = imports.signals;
const Utils = imports.utils;
+const MAX_NICK_CHARS = 8;
+const IGNORE_STATUS_TIME = 5;
+
+const SCROLL_TIMEOUT = 100; // ms
+
+const TIMESTAMP_INTERVAL = 300; // seconds of inactivity after which to
+ // insert a timestamp
+
+const INACTIVITY_THRESHOLD = 300; // a threshold in seconds used to control
+ // the visibility of status messages
+const STATUS_NOISE_MAXIMUM = 4;
+
+const NUM_INITIAL_LOG_EVENTS = 50; // number of log events to fetch on start
+const NUM_LOG_EVENTS = 10; // number of log events to fetch when requesting more
+
const MARGIN = 14;
+const NICK_SPACING = 14; // space after nicks, matching the following elements
+ // of the nick button in the entry area:
+ // 8px padding + 6px spacing
+
+const NICKTAG_PREFIX = 'nick';
+
const ResultTextView = new Lang.Class({
Name: 'ResultTextView',
@@ -24,6 +45,93 @@ const ResultTextView = new Lang.Class({
_init: function(params) {
this.parent(params);
+
+ this.buffer.connect('mark-set', Lang.bind(this, this._onMarkSet));
+ this.connect('screen-changed', Lang.bind(this, this._updateLayout));
+ },
+
+ vfunc_get_preferred_width: function() {
+ return [1, 1];
+ },
+
+ vfunc_style_updated: function() {
+ let context = this.get_style_context();
+ context.save();
+ context.add_class('dim-label');
+ context.set_state(Gtk.StateFlags.NORMAL);
+ this._dimColor = context.get_color(context.get_state());
+ context.restore();
+
+ this.parent();
+ },
+
+ vfunc_draw: function(cr) {
+ this.parent(cr);
+
+ let mark = this.buffer.get_mark('indicator-line');
+ if (!mark) {
+ cr.$dispose();
+ return Gdk.EVENT_PROPAGATE;
+ }
+
+ let iter = this.buffer.get_iter_at_mark(mark);
+ let location = this.get_iter_location(iter);
+ let [, y] = this.buffer_to_window_coords(Gtk.TextWindowType.TEXT,
+ location.x, location.y);
+
+ let tags = iter.get_tags();
+ let pixelsAbove = tags.reduce(function(prev, current) {
+ return Math.max(prev, current.pixels_above_lines);
+ }, this.get_pixels_above_lines());
+ let pixelsBelow = tags.reduce(function(prev, current) {
+ return Math.max(prev, current.pixels_below_lines);
+ }, this.get_pixels_below_lines());
+
+ let lineSpace = Math.floor((pixelsAbove + pixelsBelow) / 2);
+ y = y - lineSpace + 0.5;
+
+ let width = this.get_allocated_width() - 2 * MARGIN;
+
+ let [, extents] = this._layout.get_pixel_extents();
+ let layoutWidth = extents.width + 0.5;
+ let layoutX = extents.x + Math.floor((width - extents.width) / 2) + 0.5;
+ let layoutHeight = extents.height;
+ let baseline = Math.floor(this._layout.get_baseline() / Pango.SCALE);
+ let layoutY = y - baseline + Math.floor((layoutHeight - baseline) / 2) + 0.5;
+
+ let [hasClip, clip] = Gdk.cairo_get_clip_rectangle(cr);
+ if (hasClip &&
+ clip.y <= layoutY + layoutHeight &&
+ clip.y + clip.height >= layoutY) {
+
+ Gdk.cairo_set_source_rgba(cr, this._dimColor);
+
+ cr.moveTo(layoutX, layoutY);
+ PangoCairo.show_layout(cr, this._layout);
+
+ let [, color] = this.get_style_context().lookup_color('borders');
+ Gdk.cairo_set_source_rgba(cr, color);
+
+ cr.setLineWidth(1);
+ cr.moveTo(MARGIN, y);
+ cr.lineTo(layoutX - MARGIN, y);
+ cr.moveTo(layoutX + layoutWidth + MARGIN, y);
+ cr.lineTo(MARGIN + width, y);
+ cr.stroke();
+ }
+ cr.$dispose();
+
+ return Gdk.EVENT_PROPAGATE;
+ },
+
+ _onMarkSet: function(buffer, iter, mark) {
+ if (mark.name == 'indicator-line')
+ this.queue_draw();
+ },
+
+ _updateLayout: function() {
+ this._layout = this.create_pango_layout(null);
+ this._layout.set_markup('<small><b>%s</b></small>'.format(_("New Messages")), -1);
}
});
@@ -44,5 +152,574 @@ const ResultView = new Lang.Class({
Gdk.EventMask.ENTER_NOTIFY_MASK);
this.add(this._view);
this.show_all();
+
+ this._active = false;
+ this._toplevelFocus = false;
+ this._fetchingBacklog = false;
+ this._joinTime = 0;
+ this._maxNickChars = MAX_NICK_CHARS;
+ this._needsIndicator = true;
+ this._pending = {};
+ this._pendingLogs = [];
+ this._logWalker = null;
+
+ this._createTags();
+
+ this.connect('style-updated',
+ Lang.bind(this, this._onStyleUpdated));
+ this._onStyleUpdated();
+
+ this.connect('screen-changed',
+ Lang.bind(this, this._updateIndent));
+ this.connect('scroll-event', Lang.bind(this, this._onScroll));
+
+ this.vadjustment.connect('changed',
+ Lang.bind(this, this._updateScroll));
+
+ this._view.connect('key-press-event', Lang.bind(this, this._onKeyPress));
+ /* pick up DPI changes (e.g. via the 'text-scaling-factor' setting):
+ the default handler calls pango_cairo_context_set_resolution(), so
+ update the indent after that */
+ this._view.connect_after('style-updated',
+ Lang.bind(this, this._updateIndent));
+
+ let adj = this.vadjustment;
+ this._scrollBottom = adj.upper - adj.page_size;
+
+ this._hoverCursor = Gdk.Cursor.new(Gdk.CursorType.HAND1);
+
+ },
+
+ _createTags: function() {
+ let buffer = this._view.get_buffer();
+ let tagTable = buffer.get_tag_table();
+ let tags = [
+ { name: 'nick',
+ left_margin: MARGIN },
+ { name: 'gap',
+ pixels_above_lines: 10 },
+ { name: 'message',
+ indent: 0 },
+ { name: 'highlight',
+ weight: Pango.Weight.BOLD },
+ { name: 'status',
+ left_margin: MARGIN,
+ indent: 0,
+ justification: Gtk.Justification.RIGHT },
+ { name: 'timestamp',
+ left_margin: MARGIN,
+ indent: 0,
+ weight: Pango.Weight.BOLD,
+ justification: Gtk.Justification.RIGHT },
+ { name: 'action',
+ left_margin: MARGIN },
+ { name: 'url',
+ underline: Pango.Underline.SINGLE },
+ { name: 'indicator-line',
+ pixels_above_lines: 24 },
+ { name: 'loading',
+ justification: Gtk.Justification.CENTER }
+ ];
+ tags.forEach(function(tagProps) {
+ tagTable.add(new Gtk.TextTag(tagProps));
+ });
+ },
+
+ _onStyleUpdated: function() {
+ let context = this.get_style_context();
+ context.save();
+ context.add_class('dim-label');
+ context.set_state(Gtk.StateFlags.NORMAL);
+ let dimColor = context.get_color(context.get_state());
+ context.restore();
+
+ context.save();
+ context.set_state(Gtk.StateFlags.LINK);
+ let linkColor = context.get_color(context.get_state());
+ this._activeNickColor = context.get_color(context.get_state());
+
+ context.set_state(Gtk.StateFlags.LINK | Gtk.StateFlags.PRELIGHT);
+ this._hoveredLinkColor = context.get_color(context.get_state());
+ context.restore();
+
+ let desaturatedNickColor = (this._activeNickColor.red +
+ this._activeNickColor.blue +
+ this._activeNickColor.green) / 3;
+ this._inactiveNickColor = new Gdk.RGBA ({ red: desaturatedNickColor,
+ green: desaturatedNickColor,
+ blue: desaturatedNickColor,
+ alpha: 1.0 });
+ if (this._activeNickColor.equal(this._inactiveNickColor))
+ this._inactiveNickColor.alpha = 0.5;
+
+ context.save();
+ context.add_class('view');
+ context.set_state(Gtk.StateFlags.NORMAL);
+ this._statusHeaderHoverColor = context.get_color(context.get_state());
+ context.restore();
+
+ let buffer = this._view.get_buffer();
+ let tagTable = buffer.get_tag_table();
+ let tags = [
+ { name: 'status',
+ foreground_rgba: dimColor },
+ { name: 'timestamp',
+ foreground_rgba: dimColor },
+ { name: 'action',
+ foreground_rgba: dimColor },
+ { name: 'url',
+ foreground_rgba: linkColor }
+ ];
+ tags.forEach(function(tagProps) {
+ let tag = tagTable.lookup(tagProps.name);
+ for (let prop in tagProps) {
+ if (prop == 'name')
+ continue;
+ tag[prop] = tagProps[prop];
+ }
+ });
+
+ let offset = NICKTAG_PREFIX.length;
+ tagTable.foreach(Lang.bind(this, function(tag) {
+ if (tag._status)
+ this._setNickStatus(tag.name.substring(offset), tag._status);
+ }));
+ },
+
+ vfunc_destroy: function() {
+ this.parent();
+ },
+
+ _onLogEventsReady: function(events) {
+ this._hideLoadingIndicator();
+
+ this._pendingLogs = events.concat(this._pendingLogs);
+ this._insertPendingLogs();
+ this._fetchingBacklog = false;
+ },
+
+ _insertPendingLogs: function() {
+ if (this._pendingLogs.length == 0)
+ return;
+
+ let index = -1;
+ let nick = this._pendingLogs[0].sender;
+ let type = this._pendingLogs[0].messageType;
+ if (!this._logWalker.isEnd()) {
+ for (let i = 0; i < this._pendingLogs.length; i++)
+ if (this._pendingLogs[i].sender != nick ||
+ this._pendingLogs[i].messageType != type) {
+ index = i;
+ break;
+ }
+ } else {
+ index = 0;
+ }
+
+ if (index < 0)
+ return;
+
+ let pending = this._pendingLogs.splice(index);
+ let state = { lastNick: null, lastTimestamp: 0 };
+ let iter = this._view.buffer.get_start_iter();
+ for (let i = 0; i < pending.length; i++) {
+ let message = { nick: pending[i].sender,
+ text: pending[i].message,
+ timestamp: pending[i].timestamp,
+ messageType: pending[i].messageType,
+ shouldHighlight: false };
+ this._insertMessage(iter, message, state);
+ this._setNickStatus(message.nick, Tp.ConnectionPresenceType.OFFLINE);
+
+ if (!iter.is_end() || i < pending.length - 1)
+ this._view.buffer.insert(iter, '\n', -1);
+ }
+
+ if (!this._channel)
+ return;
+
+ if (this._room.type == Tp.HandleType.ROOM) {
+ let members = this._channel.group_dup_members_contacts();
+ for (let j = 0; j < members.length; j++)
+ this._setNickStatus(members[j].get_alias(),
+ Tp.ConnectionPresenceType.AVAILABLE);
+ } else {
+ this._setNickStatus(this._channel.connection.self_contact.get_alias(),
+ Tp.ConnectionPresenceType.AVAILABLE);
+ this._setNickStatus(this._channel.target_contact.get_alias(),
+ Tp.ConnectionPresenceType.AVAILABLE);
+ }
+ },
+
+ get _nPending() {
+ return Object.keys(this._pending).length;
+ },
+
+ _updateIndent: function() {
+ let context = this._view.get_pango_context();
+ let metrics = context.get_metrics(null, null);
+ let charWidth = Math.max(metrics.get_approximate_char_width(),
+ metrics.get_approximate_digit_width());
+ let pixelWidth = Pango.units_to_double(charWidth);
+
+ let totalWidth = this._maxNickChars * pixelWidth + NICK_SPACING;
+
+ let tabs = Pango.TabArray.new(1, true);
+ tabs.set_tab(0, Pango.TabAlign.LEFT, totalWidth);
+ this._view.tabs = tabs;
+ this._view.indent = -totalWidth;
+ this._view.left_margin = MARGIN + totalWidth;
+ },
+
+ _ensureLogWalker: function() {
+ if (this._logWalker)
+ return;
+
+ let logManager = LogManager.getDefault();
+ this._logWalker = logManager.walkEvents(this._room.account,
+ this._room.channel_name);
+
+ this._fetchingBacklog = true;
+ this._logWalker.getEvents(NUM_INITIAL_LOG_EVENTS,
+ Lang.bind(this, this._onLogEventsReady));
+ },
+
+ _updateScroll: function() {
+ let adj = this.vadjustment;
+ if (adj.value == this._scrollBottom) {
+ if (this._nPending == 0) {
+ this._view.emit('move-cursor',
+ Gtk.MovementStep.BUFFER_ENDS, 1, false);
+ } else {
+ let id = Object.keys(this._pending).sort(function(a, b) {
+ return a - b;
+ })[0];
+ this._view.scroll_mark_onscreen(this._pending[id]);
+ }
+ }
+ this._scrollBottom = adj.upper - adj.page_size;
+ },
+
+ _onScroll: function(w, event) {
+ let [hasDir, dir] = event.get_scroll_direction();
+ if (hasDir && dir != Gdk.ScrollDirection.UP)
+ return Gdk.EVENT_PROPAGATE;
+
+ let [hasDeltas, dx, dy] = event.get_scroll_deltas();
+ if (hasDeltas && dy >= 0)
+ return Gdk.EVENT_PROPAGATE;
+
+ return this._fetchBacklog();
+ },
+
+ _onKeyPress: function(w, event) {
+ let [, keyval] = event.get_keyval();
+
+ if (keyval === Gdk.KEY_Home ||
+ keyval === Gdk.KEY_KP_Home) {
+ this._view.emit('move-cursor',
+ Gtk.MovementStep.BUFFER_ENDS,
+ -1, false);
+ return Gdk.EVENT_STOP;
+ } else if (keyval === Gdk.KEY_End ||
+ keyval === Gdk.KEY_KP_End) {
+ this._view.emit('move-cursor',
+ Gtk.MovementStep.BUFFER_ENDS,
+ 1, false);
+ return Gdk.EVENT_STOP;
+ }
+
+ if (keyval != Gdk.KEY_Up &&
+ keyval != Gdk.KEY_KP_Up &&
+ keyval != Gdk.KEY_Page_Up &&
+ keyval != Gdk.KEY_KP_Page_Up)
+ return Gdk.EVENT_PROPAGATE;
+
+ return this._fetchBacklog();
+ },
+
+ _fetchBacklog: function() {
+ if (this.vadjustment.value != 0 ||
+ this._logWalker.isEnd())
+ return Gdk.EVENT_PROPAGATE;
+
+ if (this._fetchingBacklog)
+ return Gdk.EVENT_STOP;
+
+ this._fetchingBacklog = true;
+ this._showLoadingIndicator();
+ Mainloop.timeout_add(500, Lang.bind(this,
+ function() {
+ this._logWalker.getEvents(NUM_LOG_EVENTS,
+ Lang.bind(this, this._onLogEventsReady));
+ return GLib.SOURCE_REMOVE;
+ }));
+ return Gdk.EVENT_STOP;
+ },
+
+ _showUrlContextMenu: function(url, button, time) {
+ let menu = new Gtk.Menu();
+
+ let item = new Gtk.MenuItem({ label: _("Open Link") });
+ item.connect('activate', function() {
+ Utils.openURL(url, Gtk.get_current_event_time());
+ });
+ menu.append(item);
+
+ item = new Gtk.MenuItem({ label: _("Copy Link Address") });
+ item.connect('activate',
+ function() {
+ let clipboard = Gtk.Clipboard.get_default(item.get_display());
+ clipboard.set_text(url, -1);
+ });
+ menu.append(item);
+
+ menu.show_all();
+ menu.popup(null, null, null, button, time);
+ },
+
+ _showLoadingIndicator: function() {
+ let indicator = new Gtk.Image({ icon_name: 'content-loading-symbolic',
+ visible: true });
+
+ let buffer = this._view.buffer;
+ let iter = buffer.get_start_iter();
+ let anchor = buffer.create_child_anchor(iter);
+ this._view.add_child_at_anchor(indicator, anchor);
+ buffer.insert(iter, '\n', -1);
+
+ let start = buffer.get_start_iter();
+ buffer.remove_all_tags(start, iter);
+ buffer.apply_tag(this._lookupTag('loading'), start, iter);
+ },
+
+ _hideLoadingIndicator: function() {
+ let buffer = this._view.buffer;
+ let iter = buffer.get_start_iter();
+
+ if (!iter.get_child_anchor())
+ return;
+
+ iter.forward_line();
+ buffer.delete(buffer.get_start_iter(), iter);
+ },
+
+ _formatTimestamp: function(timestamp) {
+ let date = GLib.DateTime.new_from_unix_local(timestamp);
+ let now = GLib.DateTime.new_now_local();
+
+ // 00:01 actually, just to be safe
+ let todayMidnight = GLib.DateTime.new_local(now.get_year(),
+ now.get_month(),
+ now.get_day_of_month(),
+ 0, 1, 0);
+ let dateMidnight = GLib.DateTime.new_local(date.get_year(),
+ date.get_month(),
+ date.get_day_of_month(),
+ 0, 1, 0);
+ let daysAgo = todayMidnight.difference(dateMidnight) / GLib.TIME_SPAN_DAY;
+
+ let format;
+ let desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
+ let clockFormat = desktopSettings.get_string('clock-format');
+ let hasAmPm = date.format('%p') != '';
+
+ if (clockFormat == '24h' || !hasAmPm) {
+ if(daysAgo < 1) { // today
+ /* Translators: Time in 24h format */
+ format = _("%H\u2236%M");
+ } else if(daysAgo <2) { // yesterday
+ /* Translators: this is the word "Yesterday" followed by a
+ time string in 24h format. i.e. "Yesterday, 14:30" */
+ // xgettext:no-c-format
+ format = _("Yesterday, %H\u2236%M");
+ } else if (daysAgo < 7) { // this week
+ /* Translators: this is the week day name followed by a time
+ string in 24h format. i.e. "Monday, 14:30" */
+ // xgettext:no-c-format
+ format = _("%A, %H\u2236%M");
+ } else if (date.get_year() == now.get_year()) { // this year
+ /* Translators: this is the month name and day number
+ followed by a time string in 24h format.
+ i.e. "May 25, 14:30" */
+ // xgettext:no-c-format
+ format = _("%B %d, %H\u2236%M");
+ } else { // before this year
+ /* Translators: this is the month name, day number, year
+ number followed by a time string in 24h format.
+ i.e. "May 25 2012, 14:30" */
+ // xgettext:no-c-format
+ format = _("%B %d %Y, %H\u2236%M");
+ }
+ } else {
+ if(daysAgo < 1) { // today
+ /* Translators: Time in 12h format */
+ format = _("%l\u2236%M %p");
+ } else if(daysAgo <2) { // yesterday
+ /* Translators: this is the word "Yesterday" followed by a
+ time string in 12h format. i.e. "Yesterday, 2:30 pm" */
+ // xgettext:no-c-format
+ format = _("Yesterday, %l\u2236%M %p");
+ } else if (daysAgo < 7) { // this week
+ /* Translators: this is the week day name followed by a time
+ string in 12h format. i.e. "Monday, 2:30 pm" */
+ // xgettext:no-c-format
+ format = _("%A, %l\u2236%M %p");
+ } else if (date.get_year() == now.get_year()) { // this year
+ /* Translators: this is the month name and day number
+ followed by a time string in 12h format.
+ i.e. "May 25, 2:30 pm" */
+ // xgettext:no-c-format
+ format = _("%B %d, %l\u2236%M %p");
+ } else { // before this year
+ /* Translators: this is the month name, day number, year
+ number followed by a time string in 12h format.
+ i.e. "May 25 2012, 2:30 pm"*/
+ // xgettext:no-c-format
+ format = _("%B %d %Y, %l\u2236%M %p");
+ }
+ }
+
+ return date.format(format);
+ },
+
+ _insertMessage: function(iter, message, state) {
+ let isAction = message.messageType == Tp.ChannelTextMessageType.ACTION;
+ let needsGap = message.nick != state.lastNick || isAction;
+
+ if (message.timestamp - TIMESTAMP_INTERVAL > state.lastTimestamp) {
+ let tags = [this._lookupTag('timestamp')];
+ if (needsGap)
+ tags.push(this._lookupTag('gap'));
+ needsGap = false;
+ this._insertWithTags(iter,
+ this._formatTimestamp(message.timestamp) + '\n',
+ tags);
+ }
+ state.lastTimestamp = message.timestamp;
+
+ this._updateMaxNickChars(message.nick.length);
+
+ let tags = [];
+ if (isAction) {
+ message.text = "%s %s".format(message.nick, message.text);
+ state.lastNick = null;
+ tags.push(this._lookupTag('action'));
+ if (needsGap)
+ tags.push(this._lookupTag('gap'));
+ } else {
+ if (state.lastNick != message.nick) {
+ let tags = [this._lookupTag('nick')];
+ let nickTagName = this._getNickTagName(message.nick);
+ let nickTag = this._lookupTag(nickTagName);
+
+ if (!nickTag) {
+ nickTag = new Gtk.TextTag({ name: nickTagName });
+ this._view.get_buffer().get_tag_table().add(nickTag);
+ }
+ tags.push(nickTag);
+ if (needsGap)
+ tags.push(this._lookupTag('gap'));
+ this._insertWithTags(iter, message.nick + '\t', tags);
+ }
+ state.lastNick = message.nick;
+ tags.push(this._lookupTag('message'));
+ }
+
+ if (message.shouldHighlight)
+ tags.push(this._lookupTag('highlight'));
+
+ let params = this._room.account.dup_parameters_vardict().deep_unpack();
+ let server = params.server.deep_unpack();
+
+ let text = message.text;
+ let channels = Utils.findChannels(text, server);
+ let urls = Utils.findUrls(text).concat(channels).sort((u1,u2) => u1.pos - u2.pos);
+ let pos = 0;
+ for (let i = 0; i < urls.length; i++) {
+ let url = urls[i];
+ this._insertWithTags(iter, text.substr(pos, url.pos - pos), tags);
+
+ let tag = this._createUrlTag(url.url);
+ this._view.get_buffer().tag_table.add(tag);
+
+ let name = url.name ? url.name : url.url;
+ this._insertWithTags(iter, name,
+ tags.concat(this._lookupTag('url'), tag));
+
+ pos = url.pos + name.length;
+ }
+ this._insertWithTags(iter, text.substr(pos), tags);
+ },
+
+ _createUrlTag: function(url) {
+ if (url.indexOf(':') == -1)
+ url = 'http://' + url;
+
+ let tag = new ButtonTag();
+ tag.connect('notify::hover', Lang.bind(this,
+ function() {
+ tag.foreground_rgba = tag.hover ? this._hoveredLinkColor : null;
+ }));
+ tag.connect('clicked',
+ function() {
+ Utils.openURL(url, Gtk.get_current_event_time());
+ });
+ tag.connect('button-press-event', Lang.bind(this,
+ function(tag, event) {
+ let [, button] = event.get_button();
+ if (button != Gdk.BUTTON_SECONDARY)
+ return Gdk.EVENT_PROPAGATE;
+
+ this._showUrlContextMenu(url, button, event.get_time());
+ return Gdk.EVENT_STOP;
+ }));
+ return tag;
+ },
+
+ _ensureNewLine: function() {
+ let buffer = this._view.get_buffer();
+ let iter = buffer.get_end_iter();
+ let tags = [];
+ let groupTag = this._lookupTag('status' + this._state.lastStatusGroup);
+ if (groupTag && iter.ends_tag(groupTag))
+ tags.push(groupTag);
+ let headerTag = this._lookupTag('status-compressed' + this._state.lastStatusGroup);
+ if (headerTag && iter.ends_tag(headerTag))
+ tags.push(headerTag);
+ if (iter.get_line_offset() != 0)
+ this._insertWithTags(iter, '\n', tags);
+ },
+
+ _getLineIters: function(iter) {
+ let start = iter.copy();
+ start.backward_line();
+ start.forward_to_line_end();
+
+ let end = iter.copy();
+ end.forward_to_line_end();
+
+ return [start, end];
+ },
+
+ _lookupTag: function(name) {
+ return this._view.get_buffer().tag_table.lookup(name);
+ },
+
+ _insertWithTagName: function(iter, text, name) {
+ this._insertWithTags(iter, text, [this._lookupTag(name)]);
+ },
+
+ _insertWithTags: function(iter, text, tags) {
+ let buffer = this._view.get_buffer();
+ let offset = iter.get_offset();
+
+ buffer.insert(iter, text, -1);
+
+ let start = buffer.get_iter_at_offset(offset);
+
+ buffer.remove_all_tags(start, iter);
+ for (let i = 0; i < tags.length; i++)
+ buffer.apply_tag(tags[i], start, iter);
}
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]