# frozen_string_literal: truemoduleListenclassQueueOptimizerclassConfigdefinitialize(adapter_class,silencer)@adapter_class=adapter_class@silencer=silencerenddefexist?(path)Pathname(path).exist?enddefsilenced?(path,type)@silencer.silenced?(path,type)enddefdebug(*args,&block)Listen.logger.debug(*args,&block)endenddefsmoosh_changes(changes)# TODO: adapter could be nil at this point (shutdown)cookies=changes.group_bydo|_,_,_,_,options|(options||{})[:cookie]end_squash_changes(_reinterpret_related_changes(cookies))enddefinitialize(config)@config=configendprivateattr_reader:config# groups changes into the expected structure expected by# clientsdef_squash_changes(changes)# We combine here for backward compatibility# Newer clients should receive dir and path separatelychanges=changes.map{|change,dir,path|[change,dir+path]}actions=changes.group_by(&:last).mapdo|path,action_list|[_logical_action_for(path,action_list.map(&:first)),path.to_s]endconfig.debug("listen: raw changes: #{actions.inspect}"){modified: [],added: [],removed: []}.tapdo|squashed|actions.eachdo|type,path|squashed[type]<<pathunlesstype.nil?endconfig.debug("listen: final changes: #{squashed.inspect}")endenddef_logical_action_for(path,actions)actions<<:addedifactions.delete(:moved_to)actions<<:removedifactions.delete(:moved_from)modified=actions.find{|x|x==:modified}_calculate_add_remove_difference(actions,path,modified)enddef_calculate_add_remove_difference(actions,path,default_if_exists)added=actions.count{|x|x==:added}removed=actions.count{|x|x==:removed}diff=added-removed# TODO: avoid checking if path exists and instead assume the events are# in order (if last is :removed, it doesn't exist, etc.)ifconfig.exist?(path)ifdiff>0:addedelsifdiff.zero?&&added>0:modifiedelsedefault_if_existsendelsediff<0?:removed:nilendend# remove extraneous rb-inotify events, keeping them only if it's a possible# editor rename() call (e.g. Kate and Sublime)def_reinterpret_related_changes(cookies)table={moved_to: :added,moved_from: :removed}cookies.flat_mapdo|_,changes|if(editor_modified=editor_modified?(changes))[[:modified,*editor_modified]]elsenot_silenced=changes.rejectdo|type,_,_,path,_|config.silenced?(Pathname(path),type)endnot_silenced.mapdo|_,change,dir,path,_|[table.fetch(change,change),dir,path]endendendenddefeditor_modified?(changes)returnunlesschanges.size==2from_type=from=nilto_type=to_dir=to=nilchanges.eachdo|data|casedata[1]when:moved_fromfrom_type,_from_change,_,from,=datawhen:moved_toto_type,_to_change,to_dir,to,=dataendend# Expect an ignored moved_from and non-ignored moved_to# to qualify as an "editor modify"iffrom&&to&&config.silenced?(Pathname(from),from_type)&&!config.silenced?(Pathname(to),to_type)[to_dir,to]endendendend