require 'runeblog' require 'ostruct' require 'helpers-repl' # FIXME structure require 'pathmagic' make_exception(:PublishError, "Error during publishing") make_exception(:EditorProblem, "Could not edit $1") module RuneBlog::REPL def edit_file(file, vim: "") STDSCR.saveback ed = @blog.editor params = vim if ed =~ /vim$/ result = system!("#{@blog.editor} #{file} #{params}") raise EditorProblem(file) unless result STDSCR.restback # cmd_clear(nil) end def cmd_quit(arg, testing = false) cmd_clear(nil) RubyText.stop sleep 0.1 sleep 0.1 exit end def cmd_clear(arg, testing = false) # STDSCR.rows.times { puts " "*(STDSCR.cols-1) } STDSCR.clear end def cmd_version(arg, testing = false) reset_output output RuneBlog::VERSION puts fx("\n RuneBlog", :bold), fx(" v #{RuneBlog::VERSION}\n", Red) unless testing @out end def cmd_config(arg, testing = false) hash = {"global.lt3 Global configuration" => "global.lt3", "banner/top.lt3 Text portion of banner" => "banner/top.lt3", "blog/generate.lt3 Generator for view (usu not edited)" => "blog/generate.lt3", ".... head.lt3 HEAD info for view" => "blog/head.lt3", ".... banner.lt3 banner description" => "blog/banner.lt3", ".... index.lt3 User-edited detail for view" => "blog/index.lt3", ".... post_entry.lt3 Generator for post entry in recent-posts" => "blog/post_entry.lt3", "etc/blog.css.lt3 Global CSS" => "etc/blog.css.lt3", "... externals.lt3 External JS/CSS (Bootstrap, etc.)" => "/etc/externals.lt3", "post/generate.lt3 Generator for a post" => "post/generate.lt3", ".... head.lt3 HEAD info for post" => "post/head.lt3", ".... index.lt3 Content for post" => "post/index.lt3", ".... permalink.lt3 Generator for permalink" => "post/permalink.lt3", } dir = @blog.view.dir/"themes/standard/" num, target = STDSCR.menu(title: "Edit file:", items: hash) edit_file(dir/target) end def cmd_manage(arg, testing = false) case arg when "pages"; _manage_pages(nil, testing = false) when "links"; _manage_links(nil, testing = false) when "navbar"; _manage_navbar(nil, testing = false) # when "pinned"; _manage_pinned(nil, testing = false) # ditch this?? else puts "#{arg} is unknown" end end def _manage_pinned(arg, testing = false) # cloned from manage_links dir = @blog.view.dir/"themes/standard/widgets/pinned" data = dir/"list.data" edit_file(data) end def _manage_navbar(arg, testing = false) # cloned from manage_pages dir = @blog.view.dir/"themes/standard/banner/navbar" files = Dir.entries(dir) - %w[. .. navbar.lt3] main_file = "[ navbar.lt3 ]" new_item = " [New item] " files = [main_file] + files + [new_item] num, fname = STDSCR.menu(title: "Edit navbar:", items: files) return if fname.nil? case fname when new_item print "Page title: " title = RubyText.gets title.chomp! print "File name (.lt3): " fname = RubyText.gets fname << ".lt3" unless fname.end_with?(".lt3") new_file = dir/fname File.open(new_file, "w") do |f| f.puts "

#{title}

\n\n\n " f.puts ".backlink" end edit_file(new_file) when main_file edit_file(main_file[2..-3]) else edit_file(dir/fname) end end def _manage_links(arg, testing = false) dir = @blog.view.dir/"themes/standard/widgets/links" data = dir/"list.data" edit_file(data) end def _manage_pages(arg, testing = false) dir = @blog.view.dir/"themes/standard/widgets/pages" # Assume child files already generated (and list.data??) data = dir/"list.data" lines = _get_data?(data) hash = {} lines.each do |line| url, name = line.chomp.split(",") source = url.sub(/.html$/, ".lt3") hash[name] = source end new_item = "[New page]" num, fname = STDSCR.menu(title: "Edit page:", items: hash.keys + [new_item]) return if fname.nil? if fname == new_item print "Page title: " title = RubyText.gets title.chomp! print "File name (.lt3): " fname = RubyText.gets fname << ".lt3" unless fname.end_with?(".lt3") fhtml = fname.sub(/.lt3$/, ".html") File.open(data, "a") {|f| f.puts "#{fhtml},#{title}" } new_file = dir/fname File.open(new_file, "w") do |f| f.puts "

#{title}

\n\n\n " f.puts ".backlink" end edit_file(new_file) else target = hash[fname] edit_file(dir/target) end end def cmd_import(arg, testing = false) files = ask("\n File(s) = ") system!("cp #{files} #{@blog.root}/views/#{@blog.view.name}/assets/") end def cmd_browse(arg, testing = false) reset_output url = @blog.view.publisher.url if url.nil? output! "Publish first." puts "\n Publish first." return @out end result = system!("open '#{url}'") raise CantOpen(url) unless result return @out end def cmd_preview(arg, testing = false) reset_output local = @blog.view.local_index unless File.exist?(local) puts "\n No index. Rebuilding..." cmd_rebuild(nil) end result = system!("open #{local}") raise CantOpen(local) unless result @out rescue => err out = "/tmp/blog#{rand(100)}.txt" File.open(out, "w") do |f| f.puts err f.puts err.backtrace.join("\n") end puts "Error: See #{out}" end def cmd_publish(arg, testing = false) # Future Hal says please refactor this puts unless testing reset_output unless @blog.view.can_publish? msg = "Can't publish... see global.lt3" puts msg unless testing output! msg return @out end ret = RubyText.spinner(label: " Publishing... ") do @blog.view.publisher.publish end return @out unless ret vdir = @blog.view.dir dump("fix this later", "#{vdir}/last_published") if ! testing || ! ret puts " ...finished.\n " output! "...finished.\n" end return @out rescue => err out = "/tmp/blog#{rand(100)}.txt" File.open(out, "w") do |f| f.puts err f.puts err.backtrace.join("\n") end puts "Error: See #{out}" end def fresh?(src, dst) return false unless File.exist?(dst) File.mtime(src) <= File.mtime(dst) end def regen_posts drafts = @blog.drafts # current view drafts.each do |draft| orig = @blog.root/:drafts/draft html = @blog.root/:posts/draft html.sub!(/.lt3$/, "/guts.html") next if fresh?(orig, html) puts " Regenerating #{draft}" @blog.generate_post(orig) # rebuild post end puts end def cmd_rebuild(arg, testing = false) debug "Starting cmd_rebuild..." reset_output puts unless testing @blog.generate_view(@blog.view) @blog.generate_index(@blog.view) regen_posts @out rescue => err out = "/tmp/blog#{rand(100)}.txt" File.open(out, "w") do |f| f.puts err f.puts err.backtrace.join("\n") end puts "Error: See #{out}" end def cmd_change_view(arg, testing = false) reset_output # Simplify this if arg.nil? viewnames = @blog.views.map {|x| x.name } n = viewnames.find_index(@blog.view.name) name = @blog.view.name # TODO: Add view description k, name = STDSCR.menu(title: "Views", items: viewnames, curr: n) unless testing return if name.nil? @blog.view = name output name + "\n" puts "\n ", fx(name, :bold), "\n" unless testing return @out else if @blog.view?(arg) @blog.view = arg output "View: " + @blog.view.name.to_s puts "\n ", fx(arg, :bold), "\n" unless testing end end return @out end def cmd_new_view(arg, testing = false) reset_output if arg.nil? arg = ask(fx("\nFilename: ", :bold)) puts end @blog.create_view(arg) text = File.read("#{@blog.root}/data/global.lt3") File.write("#{@blog.root}/views/#{@blog.view}/themes/standard/global.lt3", text.gsub(/VIEW_NAME/, @blog.view.to_s)) vim_params = '-c ":set hlsearch" -c ":hi Search ctermfg=2 ctermbg=6" +/"\(VIEW_.*\|SITE.*\)"' edit_file(@blog.view.dir/"themes/standard/global.lt3", vim: vim_params) @blog.change_view(arg) @out rescue ViewAlreadyExists puts 'Blog already exists' rescue => err out = "/tmp/blog#{rand(100)}.txt" File.open(out, "w") do |f| f.puts err f.puts err.backtrace.join("\n") end puts "Error: See #{out}" end def cmd_new_post(arg, testing = false) reset_output if @blog.views.empty? puts "\n Create a view before creating the first post!\n " return end title = ask("\nTitle: ") puts @blog.create_new_post(title) # STDSCR.clear @out rescue => err out = "/tmp/blog#{rand(100)}.txt" File.open(out, "w") do |f| f.puts err f.puts err.backtrace.join("\n") end puts "Error: See #{out}" end def _remove_post(arg, testing=false) id = get_integer(arg) result = @blog.remove_post(id) puts "Post #{id} not found" if result.nil? end def cmd_remove_post(arg, testing = false) reset_output args = arg.split args.each do |x| # FIXME ret = _remove_post(x.to_i, false) puts ret output ret end @out end def cmd_edit_post(arg, testing = false) reset_output id = get_integer(arg) # Simplify this tag = "#{'%04d' % id}" files = ::Find.find(@blog.root/:drafts).to_a files = files.grep(/#{tag}-.*lt3/) files = files.map {|f| File.basename(f) } if files.size > 1 msg = "Multiple files: #{files}" output msg puts msg unless testing return [false, msg] end if files.empty? msg = "\n Can't edit post #{id}" output msg puts msg unless testing return [false, msg] end file = files.first draft = @blog.root/:drafts/file vim_params = '-c G' result = edit_file(draft) @blog.generate_post(draft) rescue => err out = "/tmp/blog#{rand(100)}.txt" File.open(out, "w") do |f| f.puts err f.puts err.backtrace.join("\n") end puts "Error: See #{out}" end def cmd_list_views(arg, testing = false) reset_output("\n") puts unless testing @blog.views.each do |v| v = v.to_s v = fx(v, :bold) if v == @blog.view.name output v + "\n" # FIXME: next 3 lines are crufty as hell lines = File.readlines(@blog.root/"views/#{v}/themes/standard/global.lt3") lines = lines.select {|x| x =~ /^blog / && x !~ /VIEW_/ } title = lines.first.split(" ", 2)[1] print " ", ('%15s' % v) unless testing puts " ", fx(title, :black) unless testing end puts unless testing # @out end def cmd_list_posts(arg, testing = false) reset_output posts = @blog.posts # current view str = @blog.view.name + ":\n" output str puts unless testing puts " ", fx(str, :bold) unless testing if posts.empty? output! "No posts" puts " No posts" unless testing else posts.each do |post| outstr " #{colored_slug(post)}\n" base = post.sub(/.lt3$/, "") num, rest = base[0..3], base[4..-1] puts " ", fx(num, Red), fx(rest, Blue) unless testing draft = @blog.root/:drafts/post + ".lt3" other = @blog._get_views(draft) - [@blog.view.to_s] unless other.empty? print fx(" "*7 + "also in: ", :bold) puts other.join(", ") end end end puts unless testing @out end def cmd_list_drafts(arg, testing = false) reset_output drafts = @blog.drafts # current view if drafts.empty? output! "No drafts" puts "\n No drafts\n " unless testing return @out else puts unless testing drafts.each do |draft| outstr " #{colored_slug(draft.sub(/.lt3$/, ""))}\n" base = draft.sub(/.lt3$/, "") num, rest = base[0..3], base[4..-1] puts " ", fx(num, Red), fx(rest, Blue) unless testing other = @blog._get_views(@blog.root/:drafts/draft) - [@blog.view.to_s] unless other.empty? print fx(" "*7 + "also in: ", :bold) puts other.join(", ") end end end puts unless testing @out end def cmd_list_assets(arg, testing = false) reset_output dir = @blog.view.dir + "/assets" assets = Dir[dir + "/*"] if assets.empty? output! "No assets" puts " No assets" unless testing return @out else puts unless testing assets.each do |name| asset = File.basename(name) outstr asset puts " ", fx(asset, Blue) unless testing end end puts unless testing @out end def cmd_ssh(arg, testing = false) pub = @blog.view.publisher puts system!("tputs clear; ssh #{pub.user}@#{pub.server}") sleep 0.1 cmd_clear(nil) end def cmd_INVALID(arg, testing = false) reset_output "\n Command '#{arg}' was not understood." print fx("\n Command ", :bold) print fx(arg, Red, :bold) puts fx(" was not understood.\n ", :bold) @out end def cmd_legacy(arg = nil) # dir = ask("Dir = ") dir = "sources/computing" puts "Importing from: #{dir}" files = Dir[dir/"**"] files.each do |fname| name = fname cmd = "grep ^.title #{name}" grep = `#{cmd}` # find .title @title = grep.sub(/^.title /, "") num = `grep ^.post #{name}`.sub(/^.post /, "").to_i seq = @blog.get_sequence tnum = File.basename(fname).to_i raise "num != seq + 1" if num != seq + 1 raise "num != tnum" if num != tnum seq = @blog.next_sequence raise "num != seq" if num != seq label = '%04d' % num slug0 = @title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '') @slug = "#{label}-#{slug0}" @fname = @slug + ".lt3" cmd = "cp #{name} #{@blog.root}/drafts/#@fname" result = system!(cmd) raise CantCopy(name, "#{@blog.root}/drafts/#@fname") unless result # post = Post.load(@slug) draft = "#{@blog.root}/drafts/#@fname" @meta = @blog.generate_post(draft) puts sleep 2 end rescue => err error(err) end Help = <<-EOS {Basics:} {Views:} ------------------------------------------- ------------------------------------------- {h, help} This message {change view VIEW} Change current view {q, quit} Exit the program {cv VIEW} Change current view {v, version} Print version information {new view} Create a new view {clear} Clear screen {list views} List all views available {lsv} Same as: list views {Posts:} {Advanced:} ------------------------------------------- ------------------------------------------- {p, post} Create a new post {config} Edit various system files {new post} Same as p, post {customize} (BUGGY) Change set of tags, extra views {lsp, list posts} List posts in current view {preview} Look at current (local) view in browser {lsd, list drafts} List all drafts (all views) {browse} Look at current (published) view in browser {delete ID [ID...]} Remove multiple posts {rebuild} Regenerate all posts and relink {undelete ID} Undelete a post {publish} Publish (current view) {edit ID} Edit a post {ssh} Login to remote server {import ASSETS} Import assets (images, etc.) {manage WIDGET} Manage content/layout of a widget EOS def cmd_help(arg, testing = false) reset_output msg = Help output msg msg.each_line do |line| e = line.each_char first = true loop do s1 = "" c = e.next if c == "{" s2 = first ? "" : " " first = false loop do c = e.next break if c == "}" s2 << c end print fx(s2, :bold) s2 = "" else s1 << c end print s1 end end puts unless testing @out end end