/lib/plugins/defaults/standard_commands.rb
Ruby | 591 lines | 537 code | 45 blank | 9 comment | 31 complexity | 4f081bddf3af8f03e55b892aa5995eaf MD5 | raw file
- # -*- coding: utf-8 -*-
- require 'erb'
- require 'set'
- config.plugins.standard.set_default(
- :limit_format,
- '<<%=remaining_color%>><%=limit.remaining_hits%></<%=remaining_color%>>/<%=limit.hourly_limit%> until <%=Time.parse(limit.reset_time).getlocal%> (<%=remaining_time%> remaining)')
- config.set_default(:easy_reply, false)
- config.plugins.standard.set_default(
- :one_line_profile_format,
- '<90>[<%=user_id%>]</90> <%= mark %> <<%=color%>><%= user.screen_name %>: <%= padding %><%= (user.description || "").gsub(/\r?\n/, "") %></<%=color%>>')
- module Termtter::Client
- register_command(
- :name => :reload,
- :exec => lambda {|arg|
- # NOTE: If edit this command, please check and edit lib/plugins/channel.rb too, please.
- args = @since_id ? [{:since_id => @since_id}] : []
- statuses = Termtter::API.twitter.home_timeline(*args)
- unless statuses.empty?
- Termtter::Client.clear_line
- @since_id = statuses[0].id
- output(statuses, Termtter::Event.new(:update_friends_timeline, :type => :main))
- Readline.refresh_line if arg =~ /\-r/
- end
- },
- :help => ['reload', 'Reload time line']
- )
- register_command(
- :name => :update, :alias => :u,
- :exec => lambda {|arg|
- return if arg.empty?
- params =
- if config.easy_reply && /^\s*(@\w+)/ =~ arg
- user_name = normalize_as_user_name($1)
- in_reply_to_status_id =
- Termtter::API.twitter.user(user_name).status.id rescue nil
- in_reply_to_status_id ?
- {:in_reply_to_status_id => in_reply_to_status_id} : {}
- else
- {}
- end
- # "u $aa msg" is likely to be a mistake of
- # "re $aa msg".
- if /^\s*\d+\s/ =~ arg
- case HighLine.new.ask("Does it mean `re[ply] #{arg}` [N/y]? ")
- when /^[yY]$/
- Termtter::Client.execute("re #{arg}")
- break
- when /^[nN]?$/
- else
- puts "Invalid answer. Please input [yYnN] or nothing."
- break
- end
- end
- result = Termtter::API.twitter.update(arg, params)
- if result.text == arg
- puts "updated => #{result.text}"
- else
- puts TermColor.parse("<red>Failed to update :(</red>")
- end
- },
- :help => ["update,u TEXT", "Post a new message"]
- )
- register_command(
- :name => :delete, :aliases =>[:del],
- :exec_proc => lambda {|arg|
- id =
- case arg
- when ''
- Termtter::API.twitter.user_timeline(config.user_name)[0].id
- when /^\d+$/
- arg.to_i
- end
- if id
- result = Termtter::API.twitter.remove_status(id)
- puts "deleted => #{result.text}"
- end
- },
- :help => ['delete,del [STATUS ID]', 'Delete a status']
- )
- unless defined? DirectMessage
- class DirectMessage < Struct.new(:id, :text, :user, :created_at)
- def method_missing(*args, &block)
- nil
- end
- end
- end
- register_command(
- :direct, :alias => :d,
- :help => ["direct,d USERNAME TEXT", "Send direct message"]) do |arg|
- if /^([^\s]+)\s+?(.*)\s*$/ =~ arg
- user, text = normalize_as_user_name($1), $2
- Termtter::API.twitter.direct_message(user, text)
- puts "=> to:#{user} message:#{text}"
- end
- end
- register_command(
- 'direct list', :help => ["direct list", 'List direct messages']) do |arg|
- output(
- Termtter::API.twitter.direct_messages.map { |d|
- DirectMessage.new(d.id, "#{d.text} => #{d.recipient_screen_name}", d.sender, d.created_at)
- },
- Termtter::Event.new(
- :direct_messages,
- :type => :direct_message)
- )
- end
- register_command(
- 'direct sent_list',
- :help => ["direct sent_list", 'List sent direct messages']) do |arg|
- output(
- Termtter::API.twitter.sent_direct_messages.map { |d|
- DirectMessage.new(
- d.id, "#{d.text} => #{d.recipient_screen_name}", d.sender, d.created_at)
- },
- Termtter::Event.new(
- :direct_messages,
- :type => :direct_message)
- )
- end
- def self.get_friends(user_name, max)
- self.get_friends_or_followers(:friends, user_name, max)
- end
- def self.get_followers(user_name, max)
- self.get_friends_or_followers(:followers, user_name, max)
- end
- def self.get_friends_or_followers(type, user_name, max)
- raise "type should be :friends or :followers" unless [:friends, :followers].include? type
- users = []
- cursor = -1
- begin
- tmp = Termtter::API::twitter.__send__(type, user_name, :cursor => cursor)
- cursor = tmp[:next_cursor]
- users += tmp[:users]
- puts "#{users.length}/#{max}" if max > 100
- rescue
- break
- end until (cursor.zero? or users.length > max)
- users.take(max)
- end
- register_command(
- :name => :friends, :aliases => [:following],
- :exec_proc => lambda {|arg|
- friends_or_followers_command(:friends, arg)
- },
- :help => ["friends [USERNAME] [-COUNT]", "Show user's friends."]
- )
- register_command(
- :name => :followers,
- :exec_proc => lambda {|arg|
- friends_or_followers_command(:followers, arg)
- },
- :help => ["followers [USERNAME]", "Show user's followers."]
- )
- def self.friends_or_followers_command(type, arg)
- raise "type should be :friends or :followers" unless [:friends, :followers].include? type
- limit = 20
- if /\-([\d]+)/ =~ arg
- limit = $1.to_i
- arg = arg.gsub(/\-([\d]+)/, '')
- end
- arg.strip!
- user_name = arg.empty? ? config.user_name : arg
- users = get_friends_or_followers(type, user_name, limit)
- longest = users.map{ |u| u.screen_name.length}.max
- users.reverse.each{|user|
- padding = ' ' * (longest - user.screen_name.length)
- user_id = Termtter::Client.data_to_typable_id(user.id) rescue ''
- color = user.following ? config.plugins.stdout.colors.first : config.plugins.stdout.colors.last
- mark = user.following ? '♥' : '✂'
- erbed_text = ERB.new(config.plugins.standard.one_line_profile_format).result(binding)
- puts TermColor.unescape(TermColor.parse(erbed_text))
- }
- end
- class SearchEvent < Termtter::Event
- def initialize(query)
- super :search, {:query => query, :type => :search}
- end
- end
- public_storage[:search_keywords] = Set.new
- register_command(
- :name => :search, :aliases => [:s],
- :exec_proc => lambda {|arg|
- search_option = config.search.option.empty? ? {} : config.search.option
- statuses = Termtter::API.twitter.search(arg, search_option)
- public_storage[:search_keywords] << arg
- output(statuses, SearchEvent.new(arg))
- },
- :completion_proc => lambda {|cmd, arg|
- public_storage[:search_keywords].grep(/^#{Regexp.quote(arg)}/).map {|i| "#{cmd} #{i}" }
- },
- :help => ["search,s TEXT", "Search for Twitter"]
- )
- register_hook(:highlight_for_search_query, :point => :pre_coloring) do |text, event|
- case event
- when SearchEvent
- query = event.query.split(/\s/).map {|q|Regexp.quote(q)}.join("|")
- text.gsub(/#{query}/i, '<on_magenta><white>\0</white></on_magenta>')
- else
- text
- end
- end
- register_command(
- :name => :replies, :aliases => [:r],
- :exec_proc => lambda {|arg|
- if /\-([\d]+)/ =~ arg
- options = {:count => $1}
- arg = arg.gsub(/\-([\d]+)/, '')
- else
- options = {}
- end
- res = Termtter::API.twitter.replies(options)
- unless arg.empty?
- res = res.select {|e| e.user.screen_name == arg }
- end
- output(res, Termtter::Event.new(:replies, :type => :reply))
- },
- :help => ["replies,r [username]", "List the replies (from the user)"]
- )
- register_command(
- :name => :show,
- :exec_proc => lambda {|arg|
- id = arg.gsub(/.*:\s*/, '')
- output([Termtter::API.twitter.show(id)], Termtter::Event.new(:show, :type => :show))
- },
- :completion_proc => lambda {|cmd, arg|
- case arg
- when /(\w+):\s*(\d+)\s*$/
- find_status_ids($2).map {|id| "#{cmd} #{$1}: #{id}"}
- else
- users = find_users(arg)
- unless users.empty?
- users.map {|user| "#{cmd} #{user}:"}
- else
- find_status_ids(arg).map {|id| "#{cmd} #{id}"}
- end
- end
- },
- :help => ["show ID", "Show a single status"]
- )
- register_command(
- :name => :shows,
- :exec_proc => lambda {|arg|
- id = arg.gsub(/.*:\s*/, '')
- # TODO: Implement
- #output([Termtter::API.twitter.show(id)], :show)
- puts "Not implemented yet."
- },
- :completion_proc => get_command(:show).completion_proc
- )
- register_command(
- :name => :follow, :aliases => [],
- :exec_proc => lambda {|args|
- args.split(' ').each do |arg|
- user_name = normalize_as_user_name(arg)
- user = Termtter::API::twitter.follow(user_name)
- puts "followed #{user.screen_name}"
- end
- },
- :help => ['follow USER', 'Follow user']
- )
- register_command(
- :name => :leave, :aliases => [:remove],
- :exec_proc => lambda {|args|
- args.split(' ').each do |arg|
- user_name = normalize_as_user_name(arg)
- user = Termtter::API::twitter.leave(user_name)
- puts "left #{user.screen_name}"
- end
- },
- :help => ['leave USER', 'Leave user']
- )
- register_command(
- :name => :block, :aliases => [],
- :exec_proc => lambda {|args|
- args.split(' ').each do |arg|
- user_name = normalize_as_user_name(arg)
- user = Termtter::API::twitter.block(user_name)
- puts "blocked #{user.screen_name}"
- end
- },
- :help => ['block USER', 'Block user']
- )
- register_command(
- :name => :unblock, :aliases => [],
- :exec_proc => lambda {|args|
- args.split(' ').each do |arg|
- user_name = normalize_as_user_name(arg)
- user = Termtter::API::twitter.unblock(user_name)
- puts "unblocked #{user.screen_name}"
- end
- },
- :help => ['unblock USER', 'Unblock user']
- )
- help = ['favorites,favlist USERNAME', 'show user favorites']
- register_command(:favorites, :alias => :favlist, :help => help) do |arg|
- output(Termtter::API.twitter.favorites(arg), Termtter::Event.new(:user_timeline, :type => :favorite))
- end
- register_command(
- :name => :favorite, :aliases => [:fav],
- :exec_proc => lambda {|args|
- args.split(' ').each do |arg|
- id =
- case arg
- when /^\d+/
- arg.to_i
- when /^@([A-Za-z0-9_]+)/
- user_name = normalize_as_user_name($1)
- statuses = Termtter::API.twitter.user_timeline(user_name)
- return if statuses.empty?
- statuses[0].id
- when %r{twitter.com/(?:\#!/)[A-Za-z0-9_]+/status(?:es)?/\d+}
- status_id = URI.parse(arg).path.split(%{/}).last
- when %r{twitter.com/[A-Za-z0-9_]+}
- user_name = normalize_as_user_name(URI.parse(arg).path.split(%{/}).last)
- statuses = Termtter::API.twitter.user_timeline(user_name)
- return if statuses.empty?
- statuses[0].id
- when /^\/(.*)$/
- word = $1
- raise "Not implemented yet."
- else
- if public_storage[:typable_id] && typable_id?(arg)
- typable_id_convert(arg)
- else
- return
- end
- end
- begin
- r = Termtter::API.twitter.favorite id
- puts "Favorited status ##{r.id} on user @#{r.user.screen_name} #{r.text}"
- rescue => e
- handle_error e
- end
- end
- },
- :completion_proc => lambda {|cmd, arg|
- case arg
- when /(\d+)/
- find_status_ids(arg).map {|id| "#{cmd} #{id}"}
- else
- if data = Termtter::Client.typable_id_to_data(arg)
- "#{cmd} #{data}"
- else
- %w(favorite).grep(/^#{Regexp.quote arg}/)
- end
- end
- },
- :help => ['favorite,fav (ID|@USER|TYPABLE|/WORD)', 'Mark a status as a favorite']
- )
- def self.show_settings(conf, level = 0)
- conf.__values__.each do |k, v|
- if v.instance_of? Termtter::Config
- puts "#{k}:"
- show_settings v, level + 1
- else
- print ' ' * level
- puts "#{k} = #{v.nil? ? 'nil' : v.inspect}"
- end
- end
- end
- register_command(
- :name => :settings, :aliases => [:set],
- :exec_proc => lambda {|_|
- show_settings config
- },
- :help => ['settings,set', 'Show your settings']
- )
- # TODO: Change colors when remaining_hits is low.
- # TODO: Simmulate remaining_hits.
- register_command(
- :name => :limit, :aliases => [:lm],
- :exec_proc => lambda {|arg|
- limit = Termtter::API.twitter.limit_status
- remaining_time = "%dmin %dsec" % (Time.parse(limit.reset_time) - Time.now).divmod(60)
- remaining_color =
- case limit.remaining_hits / limit.hourly_limit.to_f
- when 0.2..0.4 then :yellow
- when 0..0.2 then :red
- else :green
- end
- erbed_text = ERB.new(config.plugins.standard.limit_format).result(binding)
- puts TermColor.parse(erbed_text)
- },
- :help => ["limit,lm", "Show the API limit status"]
- )
- register_command(
- :name => :pause,
- :exec_proc => lambda {|arg| pause},
- :help => ["pause", "Pause updating"]
- )
- register_command(
- :name => :resume,
- :exec_proc => lambda {|arg| resume},
- :help => ["resume", "Resume updating"]
- )
- register_command(
- :name => :exit, :aliases => [:quit],
- :exec_proc => lambda {|arg| exit},
- :help => ['exit,quit', 'Exit']
- )
- register_command(
- :name => :help, :aliases => [:h],
- :exec_proc => lambda {|arg|
- helps = []
- @commands.map do |name, command|
- next unless command.help
- case command.help[0]
- when String
- helps << command.help
- when Array
- helps += command.help
- end
- end
- helps.compact!
- unless arg.empty?
- helps = helps.select {|n, _| /#{arg}/ =~ n }
- end
- puts formatted_help(helps)
- },
- :help => ["help,h", "Print this help message"]
- )
- def self.formatted_help(helps)
- helps = helps.sort_by {|help| help[0] }
- width = helps.map {|n, _| n.size }.max
- space = 3
- helps.map {|name, desc|
- name.to_s.ljust(width + space) + desc.to_s
- }.join("\n")
- end
- register_command(
- :name => :plug,
- :alias => :plugin,
- :exec_proc => lambda {|arg|
- if arg.empty?
- puts plugin_list.join(', ')
- return
- end
- begin
- result = plug arg
- rescue LoadError
- ensure
- puts "=> #{result.inspect}"
- end
- },
- :completion_proc => lambda {|cmd, args|
- plugin_list.grep(/#{Regexp.quote(args)}/).map {|i| "#{cmd} #{i}"}
- },
- :help => ['plug FILE', 'Load a plugin']
- )
- ## plugin_list :: IO ()
- def self.plugin_list
- (Dir["#{File.dirname(__FILE__)}/../**/*.rb"] + Dir["#{Termtter::CONF_DIR}/plugins/**/*.rb"]).
- map {|f| File.expand_path(f).scan(/.*plugins\/(.*)\.rb/).flatten[0] }.
- sort
- end
- register_command(
- :name => :reply,
- :aliases => [:re],
- :exec_proc => lambda {|arg|
- case arg
- when /^\s*(?:list|ls)\s*(?:\s+(\w+))?\s*$/
- public_storage[:log4re] =
- if $1
- public_storage[:log].
- select {|l| l.user.screen_name == $1}.
- sort {|a,b| a.id <=> b.id}
- else
- public_storage[:log].sort {|a,b| a.id <=> b.id}
- end
- public_storage[:log4re].each_with_index do |s, i|
- puts "#{i}: #{s.user.screen_name}: #{s.text}"
- end
- when /^\s*(?:up(?:date)?)\s+(\d+)\s+(.+)$/
- id = public_storage[:log4re][$1.to_i].id
- text = $2
- user = public_storage[:log4re][$1.to_i].user
- update_with_user_and_id(text, user.screen_name, id) if user
- public_storage.delete :log4re
- when /^\s*(\d+)\s+(.+)$/
- s = Termtter::API.twitter.show($1) rescue nil
- if s
- update_with_user_and_id($2, s.user.screen_name, s.id)
- end
- when /^\s*(@\w+)/
- user_name = normalize_as_user_name($1)
- s = Termtter::API.twitter.user(user_name).status
- if s
- params = s ? {:in_reply_to_status_id => s.id} : {}
- Termtter::API.twitter.update(arg, params)
- puts "=> #{arg}"
- end
- else
- text = arg
- last_reply = Termtter::API.twitter.replies({:count => 1}).first
- update_with_user_and_id(text, last_reply.user.screen_name, last_reply.id)
- end
- },
- :completion_proc => lambda {|cmd, arg|
- case arg
- when /(\d+)/
- find_status_ids(arg).map {|id| "#{cmd} #{id}"}
- end
- },
- :help => ["reply,re @USERNAME or STATUS_ID", "Send a reply"]
- )
- register_command(
- :name => :redo,
- :aliases => [:"."],
- :exec_proc => lambda {|arg|
- break if Readline::HISTORY.length < 2
- i = Readline::HISTORY.length - 2
- input = ""
- begin
- input = Readline::HISTORY[i]
- i -= 1
- return if i <= 0
- end while input == "redo" or input == "."
- begin
- Termtter::Client.execute(input)
- rescue CommandNotFound => e
- warn "Unknown command \"#{e}\""
- warn 'Enter "help" for instructions'
- rescue => e
- handle_error e
- end
- },
- :help => ["redo,.", "Execute previous command"]
- )
- class << self
- def update_with_user_and_id(text, username, id)
- text = "@#{username} #{text}"
- result = Termtter::API.twitter.update(text, {'in_reply_to_status_id' => id })
- puts "replied => #{result.text}"
- end
- def normalize_as_user_name(text)
- text.strip.sub(/^@/, '')
- end
- def find_status_ids(text)
- public_storage[:status_ids].select {|id| /#{Regexp.quote(text)}/ =~ id.to_s }
- end
- def find_users(text)
- public_storage[:users].select {|user| /^#{Regexp.quote(text)}/ =~ user }
- end
- end
- end