diff options
-rw-r--r-- | core/lib/retriever.rb | 1 | ||||
-rw-r--r-- | core/lib/retriever/model.rb | 4 | ||||
-rw-r--r-- | core/mui/cairo_cell_renderer_message.rb | 8 | ||||
-rw-r--r-- | core/plugin/intent/intent.rb | 53 | ||||
-rw-r--r-- | core/plugin/intent/model/intent_token.rb | 33 | ||||
-rw-r--r-- | core/plugin/openimg/window.rb | 2 | ||||
-rw-r--r-- | core/system/message.rb | 4 | ||||
-rw-r--r-- | core/user.rb | 2 |
8 files changed, 82 insertions, 25 deletions
diff --git a/core/lib/retriever.rb b/core/lib/retriever.rb index 20da1288..9c557065 100644 --- a/core/lib/retriever.rb +++ b/core/lib/retriever.rb @@ -4,6 +4,7 @@ module Retriever # _model_slug_ をslugとして持つModelクラスを返す。 # 見つからない場合、nilを返す。 def self.Model(model_slug) + model_slug = model_slug.to_sym ObjectSpace.each_object(Retriever::Model.singleton_class) do |klass| return klass if klass.slug == model_slug end diff --git a/core/lib/retriever/model.rb b/core/lib/retriever/model.rb index 7fbf1d09..0519307a 100644 --- a/core/lib/retriever/model.rb +++ b/core/lib/retriever/model.rb @@ -85,7 +85,7 @@ class Retriever::Model end define_method("#{field_name}=") do |value| - @value[field_name] = value + @value[field_name] = Retriever::Model.cast(value, type, required) self.class.store_datum(self) value end @@ -372,7 +372,7 @@ class Retriever::Model self.class.keys.each{ |column| key, type, required = *column begin - Retriever::Model.cast(self.fetch(key), type, required) + @value[key.to_sym] = Retriever::Model.cast(self.fetch(key), type, required) rescue Retriever::InvalidTypeError=>e estr = e.to_s + "\nin #{self.fetch(key).inspect} of #{key}" warn estr diff --git a/core/mui/cairo_cell_renderer_message.rb b/core/mui/cairo_cell_renderer_message.rb index 4ecfb9d4..e93bf2a7 100644 --- a/core/mui/cairo_cell_renderer_message.rb +++ b/core/mui/cairo_cell_renderer_message.rb @@ -128,10 +128,10 @@ module Gtk return render_message(record.message) else self.pixbuf = GdkPixbuf::Pixbuf.new(file: Skin.get('notfound.png')) end - rescue Exception => e - error e - if Mopt.debug - raise e end + rescue Exception => err + error "#{err.class} by uri: #{uri} model: #{record ? record.message.inspect : nil}" + raise if Mopt.debug + error err self.pixbuf = GdkPixbuf::Pixbuf.new(file: Skin.get('notfound.png')) end private diff --git a/core/plugin/intent/intent.rb b/core/plugin/intent/intent.rb index 12cc69fc..4d3d9bf6 100644 --- a/core/plugin/intent/intent.rb +++ b/core/plugin/intent/intent.rb @@ -20,6 +20,11 @@ Plugin.create(:intent) do defevent :intent_select, prototype: [Enumerable, tcor(URI, String, Retriever::Model)] + # IntentTokenの次にあたるintentを発生させる。 + defevent :intent_forward, + priority: :ui_response, + prototype: [Plugin::Intent::IntentToken] + # _model_ を開く方法を新しく登録する。 # ==== Args # [model] サポートするModelのClass @@ -63,30 +68,43 @@ Plugin.create(:intent) do end end + on_intent_forward do |intent_token| + case intent_token[:source] + when Retriever::Model + open_model(intent_token[:source], token: intent_token) + else + open_uri(intent_token.uri, token: intent_token) + end + end + # _uri_ をUI上で開く。 # このメソッドが呼ばれたらIntentTokenを生成して、開くことを試みる。 # open_modelのほうが高速なので、modelオブジェクトが存在するならばopen_modelを呼ぶこと。 # ==== Args # [uri] 対象となるURI - def open_uri(uri) + # [token:] 親となるIntentToken + def open_uri(uri, token: nil) model_slugs = Plugin.filtering(:model_of_uri, uri.freeze, Set.new).last if model_slugs.empty? error "model not found to open for #{uri}" return end - intents = model_slugs.inject(Set.new) do |memo, model_slug| - memo.merge(Plugin.filtering(:intent_select_by_model_slug, model_slug, Set.new).last) + intents = model_slugs.lazy.flat_map{|model_slug| + Plugin.filtering(:intent_select_by_model_slug, model_slug, []).last + } + if token + intents = intents.reject{|intent| token.intent_ancestors.include?(intent) } end - if intents.empty? + head = intents.first(2) + case head.size + when 0 error "intent not found to open for #{model_slugs.to_a}" return - end - if intents.size == 1 - intent = intents.to_a.first + when 1 Plugin::Intent::IntentToken.open( uri: uri, - intent: intent, - parent: nil) + intent: head.first, + parent: token) else Plugin.call(:intent_select, intents, uri) end @@ -98,16 +116,23 @@ Plugin.create(:intent) do # このメソッドはヒントとして _model_ を与えるため、探索が発生せず高速に処理できる。 # ==== Args # [model] 対象となるRetriever::Model - def open_model(model) + def open_model(model, token: nil) intents = Plugin.filtering(:intent_select_by_model_slug, model.class.slug, Set.new).last - # TODO: intents をユーザに選択させる - if intents.size == 1 - intent = intents.to_a.first + if token + intents = intents.reject{|intent| token.intent_ancestors.include?(intent) } + end + head = intents.first(2) + case head.size + when 0 + type_strict model.uri => URI + open_uri(model.uri, token: token) + when 1 + intent = head.first Plugin::Intent::IntentToken.open( uri: model.uri, model: model, intent: intent, - parent: nil) + parent: token) else Plugin.call(:intent_select, intents, model) end diff --git a/core/plugin/intent/model/intent_token.rb b/core/plugin/intent/model/intent_token.rb index 2279c0ce..f22b0fa8 100644 --- a/core/plugin/intent/model/intent_token.rb +++ b/core/plugin/intent/model/intent_token.rb @@ -2,15 +2,21 @@ module Plugin::Intent class IntentToken < Retriever::Model - field.string :uri, required: true + field.uri :uri, required: true field.has :model, Retriever::Model field.has :intent, Plugin::Intent::Intent, required: true + field.has :parent, Plugin::Intent::IntentToken # 引数の情報からIntentTokenを作成し、それを開く def self.open(*args) self.new(*args).open end + def initialize(*rest) + super + self[:source] = self[:model] + end + # 設定された情報を使ってURI又はModelを開く def open if model? @@ -25,5 +31,30 @@ module Plugin::Intent end self end + + def forward + Plugin.call(:intent_forward, self) + end + + # _self_ から親のIntentTokenを再帰的に遡って、そのIntentTokenを引数に繰り返すEnumeratorを返す。 + # ==== Return + # [Enumerator] IntentTokenを列挙する + def ancestors + Enumerator.new do |yielder| + cur = self + loop do + break unless cur + yielder << cur + cur = cur.parent + end + end + end + + # ancestorsと同じようなもの。ただし、IntentToken#intentに関して繰り返す。 + # ==== Return + # [Enumerator] Intentを列挙する + def intent_ancestors + ancestors.lazy.map(&:intent) + end end end diff --git a/core/plugin/openimg/window.rb b/core/plugin/openimg/window.rb index ee57f07a..1d5517d3 100644 --- a/core/plugin/openimg/window.rb +++ b/core/plugin/openimg/window.rb @@ -142,7 +142,7 @@ module Plugin::Openimg def gen_browser_clicked proc do - Plugin.call(:open, @next_opener) + @next_opener.forward false end end diff --git a/core/system/message.rb b/core/system/message.rb index 10cbe864..3f0389a1 100644 --- a/core/system/message.rb +++ b/core/system/message.rb @@ -11,8 +11,8 @@ class Mikutter::System::Message < Retriever::Model field.string :description, required: true field.has :user, Mikutter::System::User, required: true - field.string :created - field.string :modified + field.time :created + field.time :modified entity_class Retriever::Entity::URLEntity diff --git a/core/user.rb b/core/user.rb index 7d247c82..6c4e7976 100644 --- a/core/user.rb +++ b/core/user.rb @@ -20,7 +20,7 @@ class User < Retriever::Model # detail | detail # profile_image_url | icon - field.string :id + field.int :id field.string :idname field.string :name field.string :location |