Module: Rcurses::EmojiPicker
- Extended by:
- Input
- Defined in:
- lib/rcurses/emoji.rb
Constant Summary collapse
- CATEGORIES =
{ "Smileys" => [ ["๐","grin"],["๐","smiley"],["๐","smile"],["๐","beaming"],["๐","laughing"], ["๐ ","sweat smile"],["๐คฃ","rofl"],["๐","joy"],["๐","slight smile"],["๐","wink"], ["๐","blush"],["๐","innocent"],["๐ฅฐ","love face"],["๐","heart eyes"],["๐คฉ","starstruck"], ["๐","kiss"],["๐","kissing"],["๐","kiss closed"],["๐","kiss smile"],["๐ฅฒ","happy tear"], ["๐","yum"],["๐","tongue"],["๐","tongue wink"],["๐คช","zany"],["๐","tongue closed"], ["๐ค","money"],["๐ค","hug"],["๐คญ","hand mouth"],["๐คซ","shush"],["๐ค","thinking"], ["๐ซก","salute"],["๐ค","zipper"],["๐คจ","raised brow"],["๐","neutral"],["๐","expressionless"], ["๐ถ","no mouth"],["๐ซฅ","dotted face"],["๐","smirk"],["๐","unamused"],["๐","roll eyes"], ["๐ฌ","grimace"],["๐ฎโ๐จ","exhale"],["๐คฅ","liar"],["๐","relieved"],["๐","pensive"], ["๐ช","sleepy"],["๐คค","drool"],["๐ด","sleep"],["๐ท","mask"],["๐ค","sick"], ["๐ค","bandage"],["๐คข","nausea"],["๐คฎ","vomit"],["๐ฅต","hot"],["๐ฅถ","cold"], ["๐ฅด","woozy"],["๐ต","dizzy"],["๐คฏ","exploding"],["๐ค ","cowboy"],["๐ฅณ","party"], ["๐ฅธ","disguise"],["๐","cool"],["๐ค","nerd"],["๐ง","monocle"],["๐","confused"], ["๐ซค","diagonal mouth"],["๐","worried"],["๐","frown"],["๐ฎ","open mouth"],["๐ฏ","hushed"], ["๐ฒ","astonished"],["๐ณ","flushed"],["๐ฅบ","pleading"],["๐ฅน","holding tears"],["๐ฆ","frowning"], ["๐ง","anguished"],["๐จ","fearful"],["๐ฐ","anxious"],["๐ฅ","sad relief"],["๐ข","cry"], ["๐ญ","sob"],["๐ฑ","scream"],["๐","confounded"],["๐ฃ","persevere"],["๐","disappointed"], ["๐","downcast"],["๐ฉ","weary"],["๐ซ","tired"],["๐ฅฑ","yawn"],["๐ค","triumph"], ["๐ก","rage"],["๐ ","angry"],["๐คฌ","swearing"],["๐","devil smile"],["๐ฟ","devil"], ["๐","skull"],["โ ๏ธ","crossbones"],["๐ฉ","poop"],["๐คก","clown"],["๐น","ogre"], ["๐ป","ghost"],["๐ฝ","alien"],["๐ค","robot"],["๐","kiss mark"],["โค๏ธ","heart"], ["๐งก","orange heart"],["๐","yellow heart"],["๐","green heart"],["๐","blue heart"], ["๐","purple heart"],["๐ค","black heart"],["๐ค","white heart"],["๐ค","brown heart"], ["๐","broken heart"],["โค๏ธโ๐ฅ","fire heart"],["๐","two hearts"],["๐","revolving hearts"], ["๐","heartbeat"],["๐","growing heart"],["๐","sparkling heart"],["๐","cupid"], ["๐","ribbon heart"],["๐","heart decoration"],["๐ซถ","heart hands"] ], "People" => [ ["๐","wave"],["๐ค","raised back"],["๐๏ธ","splayed hand"],["โ","raised hand"], ["๐","vulcan"],["๐ซฑ","right hand"],["๐ซฒ","left hand"],["๐ซณ","palm down"],["๐ซด","palm up"], ["๐","ok"],["๐ค","pinched"],["๐ค","pinch"],["โ๏ธ","peace"],["๐ค","crossed fingers"], ["๐ซฐ","index thumb"],["๐ค","love you"],["๐ค","rock"],["๐ค","call me"], ["๐","left point"],["๐","right point"],["๐","up point"],["๐","middle finger"], ["๐","down point"],["โ๏ธ","index up"],["๐ซต","point at viewer"],["๐","thumbsup"], ["๐","thumbsdown"],["โ","fist"],["๐","punch"],["๐ค","left fist"],["๐ค","right fist"], ["๐","clap"],["๐","raised hands"],["๐ซถ","heart hands"],["๐","open hands"], ["๐คฒ","palms up"],["๐ค","handshake"],["๐","pray"],["โ๏ธ","writing"],["๐ช","muscle"], ["๐ฆพ","mechanical arm"],["๐ง ","brain"],["๐","eyes"],["๐๏ธ","eye"],["๐ ","tongue"], ["๐","lips"],["๐ซฆ","biting lip"],["๐ถ","baby"],["๐ง","child"],["๐ฆ","boy"], ["๐ง","girl"],["๐ง","person"],["๐ฑ","blond"],["๐จ","man"],["๐ง","beard"], ["๐ฉ","woman"],["๐ง","older person"],["๐ด","old man"],["๐ต","old woman"] ], "Animals" => [ ["๐ถ","dog"],["๐ฑ","cat"],["๐ญ","mouse"],["๐น","hamster"],["๐ฐ","rabbit"], ["๐ฆ","fox"],["๐ป","bear"],["๐ผ","panda"],["๐ปโโ๏ธ","polar bear"],["๐จ","koala"], ["๐ฏ","tiger"],["๐ฆ","lion"],["๐ฎ","cow"],["๐ท","pig"],["๐ธ","frog"], ["๐ต","monkey"],["๐","chicken"],["๐ง","penguin"],["๐ฆ","bird"],["๐ค","chick"], ["๐ฆ","duck"],["๐ฆ ","eagle"],["๐ฆ","owl"],["๐ฆ","bat"],["๐บ","wolf"], ["๐","boar"],["๐ด","horse"],["๐ฆ","unicorn"],["๐","bee"],["๐","bug"], ["๐ฆ","butterfly"],["๐","snail"],["๐","ladybug"],["๐","ant"],["๐ชฒ","beetle"], ["๐ข","turtle"],["๐","snake"],["๐ฆ","lizard"],["๐ฆ","scorpion"],["๐","octopus"], ["๐ฆ","squid"],["๐ ","fish"],["๐","tropical fish"],["๐ก","blowfish"],["๐ฌ","dolphin"], ["๐ณ","whale"],["๐","humpback"],["๐ฆ","shark"],["๐","crocodile"],["๐ ","tiger2"], ["๐","leopard"],["๐ฆ","zebra"],["๐ฆ","gorilla"],["๐ฆง","orangutan"],["๐","elephant"], ["๐ฆ","hippo"],["๐ฆ","rhino"],["๐ช","camel"],["๐ซ","two hump camel"],["๐ฆ","giraffe"], ["๐ฆ","kangaroo"],["๐ฆฌ","bison"],["๐","water buffalo"],["๐","ox"],["๐","dairy cow"] ], "Food" => [ ["๐","apple"],["๐","pear"],["๐","orange"],["๐","lemon"],["๐","banana"], ["๐","watermelon"],["๐","grapes"],["๐","strawberry"],["๐ซ","blueberry"],["๐","melon"], ["๐","cherry"],["๐","peach"],["๐ฅญ","mango"],["๐","pineapple"],["๐ฅฅ","coconut"], ["๐ฅ","kiwi"],["๐ ","tomato"],["๐ฅ","avocado"],["๐ฝ","corn"],["๐ถ๏ธ","pepper"], ["๐ฅ","cucumber"],["๐ฅ","carrot"],["๐ง","garlic"],["๐ง ","onion"],["๐ฅ","potato"], ["๐","bread"],["๐ฅ","croissant"],["๐ฅ","baguette"],["๐ง","cheese"],["๐ฅ","egg"], ["๐ณ","cooking"],["๐ฅ","pancakes"],["๐ง","waffle"],["๐ฅ","bacon"],["๐","burger"], ["๐","fries"],["๐","pizza"],["๐ญ","hotdog"],["๐ฅช","sandwich"],["๐ฎ","taco"], ["๐ฏ","burrito"],["๐ซ","tamale"],["๐ฅ","salad"],["๐","spaghetti"],["๐","ramen"], ["๐ฒ","stew"],["๐","curry"],["๐ฃ","sushi"],["๐ฑ","bento"],["๐ฅ","dumpling"], ["๐ฉ","donut"],["๐ช","cookie"],["๐","cake"],["๐ฐ","shortcake"],["๐ง","cupcake"], ["๐ซ","chocolate"],["๐ฌ","candy"],["๐ญ","lollipop"],["๐ฎ","custard"],["๐ฏ","honey"], ["โ","coffee"],["๐ต","tea"],["๐ง","juice box"],["๐บ","beer"],["๐ป","cheers"], ["๐ฅ","champagne"],["๐ท","wine"],["๐ธ","cocktail"],["๐น","tropical drink"],["๐ง","ice"] ], "Travel" => [ ["๐ ","house"],["๐ก","garden house"],["๐ข","office"],["๐ฅ","hospital"],["๐ฆ","bank"], ["๐จ","hotel"],["๐ช","store"],["๐ซ","school"],["๐ฌ","department store"],["๐๏ธ","classical"], ["โช","church"],["๐","mosque"],["๐","synagogue"],["โฉ๏ธ","shinto"],["๐","kaaba"], ["โฒ","fountain"],["๐๏ธ","camping"],["๐๏ธ","beach"],["๐๏ธ","desert"],["๐๏ธ","island"], ["๐๏ธ","mountain"],["โฐ๏ธ","mountain2"],["๐","volcano"],["๐ป","fuji"],["๐ผ","tokyo tower"], ["๐ฝ","statue liberty"],["โ๏ธ","airplane"],["๐ฉ๏ธ","small plane"],["๐","rocket"], ["๐ธ","ufo"],["๐","helicopter"],["๐","train"],["๐","car"],["๐","taxi"], ["๐","bus"],["๐ฒ","bike"],["๐ต","scooter"],["๐ค","speedboat"],["โต","sailboat"], ["๐ข","ship"],["โ","anchor"],["๐บ๏ธ","world map"],["๐งญ","compass"],["๐","earth"], ["๐","earth americas"],["๐","earth asia"],["๐","moon"],["โญ","star"],["๐","glowing star"], ["โ๏ธ","sun"],["๐ค๏ธ","partly sunny"],["โ ","cloudy"],["๐ง๏ธ","rain"],["โ๏ธ","storm"], ["๐","rainbow"],["โ","umbrella rain"],["โ๏ธ","snowflake"],["โ","snowman"],["๐ฅ","fire"], ["๐ง","drop"],["๐","wave"] ], "Objects" => [ ["โ","watch"],["๐ฑ","phone"],["๐ป","laptop"],["โจ๏ธ","keyboard"],["๐ฅ๏ธ","desktop"], ["๐จ๏ธ","printer"],["๐ฑ๏ธ","mouse"],["๐พ","floppy"],["๐ฟ","cd"],["๐ท","camera"], ["๐ฅ","movie camera"],["๐บ","tv"],["๐ป","radio"],["๐","bell"],["๐","no bell"], ["๐ข","megaphone"],["๐ฃ","horn"],["โฐ","alarm"],["โณ","hourglass"],["๐","battery"], ["๐","plug"],["๐ก","bulb"],["๐ฆ","flashlight"],["๐ฏ๏ธ","candle"],["๐๏ธ","trash"], ["๐","key"],["๐๏ธ","old key"],["๐","lock"],["๐","unlock"],["๐จ","hammer"], ["๐ช","axe"],["โ๏ธ","pick"],["๐ง","wrench"],["๐ฉ","nut bolt"],["โ๏ธ","gear"], ["๐","paperclip"],["โ๏ธ","scissors"],["๐","pin"],["๐","round pin"],["๐๏ธ","pen"], ["โ๏ธ","pencil"],["๐","memo"],["๐","folder"],["๐","open folder"],["๐ ","calendar"], ["๐","chart"],["๐","chart up"],["๐","chart down"],["๐๏ธ","card index"], ["๐ฐ","money bag"],["๐ต","dollar"],["๐ด","yen"],["๐ถ","euro"],["๐ท","pound"], ["๐","gem"],["โ๏ธ","scales"],["๐งฐ","toolbox"],["๐งฒ","magnet"],["๐","link"], ["๐ฆ","package"],["๐ซ","mailbox"],["๐ฌ","mailbox flag"],["๐ง","email"],["๐ฉ","envelope arrow"], ["๐","gift"],["๐","ribbon"],["๐ท๏ธ","label"],["๐","bookmark"] ], "Symbols" => [ ["โ ","check"],["โ","cross"],["โ","question"],["โ","exclamation"],["โผ๏ธ","double excl"], ["โญ","circle"],["๐ซ","prohibited"],["๐ด","red circle"],["๐ ","orange circle"], ["๐ก","yellow circle"],["๐ข","green circle"],["๐ต","blue circle"],["๐ฃ","purple circle"], ["โซ","black circle"],["โช","white circle"],["๐ฅ","red square"],["๐ง","orange square"], ["๐จ","yellow square"],["๐ฉ","green square"],["๐ฆ","blue square"],["๐ช","purple square"], ["โฌ","black square"],["โฌ","white square"],["๐ถ","orange diamond"],["๐ท","blue diamond"], ["๐บ","red triangle"],["๐ป","red triangle down"],["๐ ","diamond dot"],["๐","radio button"], ["โจ","sparkles"],["โก","zap"],["๐ฅ","boom"],["๐ต","music"],["๐ถ","notes"], ["โก๏ธ","right arrow"],["โฌ ๏ธ","left arrow"],["โฌ๏ธ","up arrow"],["โฌ๏ธ","down arrow"], ["โ๏ธ","upper right"],["โ๏ธ","lower right"],["โ๏ธ","lower left"],["โ๏ธ","upper left"], ["๐","shuffle"],["๐","repeat"],["๐","repeat one"],["โถ๏ธ","play"],["โธ๏ธ","pause"], ["โน๏ธ","stop"],["โบ๏ธ","record"],["โญ๏ธ","next track"],["โฎ๏ธ","prev track"], ["๐","loud"],["๐","mute"],["๐","bell2"],["๐","pushpin"], ["โป๏ธ","recycle"],["๐","checkered flag"],["๐ฉ","flag"],["๐ณ๏ธ","white flag"], ["๐ด","black flag"],["โ ๏ธ","warning"],["๐","stop sign"],["โ","no entry"], ["โพ๏ธ","infinity"],["๐ฏ","hundred"],["๐","ok button"],["๐","new"],["๐","free"], ["โน๏ธ","info"],["๐ค","abc"],["๐ข","numbers"],["#๏ธโฃ","hash"],["*๏ธโฃ","asterisk"], ["0๏ธโฃ","zero"],["1๏ธโฃ","one"],["2๏ธโฃ","two"],["3๏ธโฃ","three"],["ยฉ๏ธ","copyright"], ["ยฎ๏ธ","registered"],["โข๏ธ","trademark"] ], "Flags" => [ ["๐ณ๐ด","norway"],["๐ธ๐ช","sweden"],["๐ฉ๐ฐ","denmark"],["๐ซ๐ฎ","finland"],["๐ฎ๐ธ","iceland"], ["๐ฌ๐ง","uk"],["๐บ๐ธ","usa"],["๐จ๐ฆ","canada"],["๐ฆ๐บ","australia"],["๐ณ๐ฟ","new zealand"], ["๐ฉ๐ช","germany"],["๐ซ๐ท","france"],["๐ช๐ธ","spain"],["๐ฎ๐น","italy"],["๐ต๐น","portugal"], ["๐ณ๐ฑ","netherlands"],["๐ง๐ช","belgium"],["๐จ๐ญ","switzerland"],["๐ฆ๐น","austria"], ["๐ต๐ฑ","poland"],["๐จ๐ฟ","czech"],["๐ฌ๐ท","greece"],["๐น๐ท","turkey"],["๐ท๐บ","russia"], ["๐บ๐ฆ","ukraine"],["๐ฏ๐ต","japan"],["๐ฐ๐ท","south korea"],["๐จ๐ณ","china"],["๐ฎ๐ณ","india"], ["๐ง๐ท","brazil"],["๐ฒ๐ฝ","mexico"],["๐ฆ๐ท","argentina"],["๐ฟ๐ฆ","south africa"], ["๐ช๐ฌ","egypt"],["๐ฎ๐ฑ","israel"],["๐ธ๐ฆ","saudi"],["๐ฆ๐ช","uae"],["๐น๐ญ","thailand"], ["๐ป๐ณ","vietnam"],["๐ฎ๐ฉ","indonesia"],["๐ต๐ญ","philippines"],["๐ฒ๐พ","malaysia"], ["๐ธ๐ฌ","singapore"],["๐ญ๐ฐ","hong kong"],["๐น๐ผ","taiwan"],["๐ณ๏ธโ๐","rainbow flag"], ["๐ดโโ ๏ธ","pirate flag"],["๐","crossed flags"],["๐","checkered"] ] }.freeze
- CELL_W =
Each emoji cell = 4 terminal columns (space + emoji + space)
4
Class Method Summary collapse
-
.pick(parent_pane) ⇒ Object
Main entry point: opens picker overlay, returns emoji string or nil.
Methods included from Input
Class Method Details
.pick(parent_pane) ⇒ Object
Main entry point: opens picker overlay, returns emoji string or nil
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/rcurses/emoji.rb', line 150 def self.pick(parent_pane) max_h, max_w = IO.console ? IO.console.winsize : [24, 80] cols = 11 ow = cols * CELL_W + 4 oh = [max_h - 4, 22].min return nil if oh < 8 ox = (max_w - ow) / 2 + 1 oy = (max_h - oh) / 2 + 1 = Rcurses::Popup.new(x: ox, y: oy, w: ow, h: oh, fg: 255, bg: 236) .scroll = false categories = CATEGORIES.keys cat_idx = 0 sel_idx = 0 search = "" fmt = "255,236" begin loop do # Determine items for current category or search if search.empty? items = CATEGORIES[categories[cat_idx]] else items = CATEGORIES.values.flatten(1).select { |_e, k| k.include?(search.downcase) } end total = items.size sel_idx = sel_idx.clamp(0, [total - 1, 0].max) # === Build pane text (header + blank grid area + footer) === lines = [] # Header: category tabs (wrapped to fit) header_lines = 0 if search.empty? tab_rows = [[]] row_w = 0 categories.each_with_index do |c, i| tab = " #{c} " tw = tab.length if row_w + tw > ow && !tab_rows.last.empty? tab_rows << [] row_w = 0 end tab_rows.last << (i == cat_idx ? tab.bd.rv : tab) row_w += tw end tab_rows.each { |tr| lines << tr.join("") } header_lines = tab_rows.size else lines << " Search: #{search}".bd header_lines = 1 end lines << "" header_lines += 1 # blank separator # Blank lines for grid area (pane fills bg color) grid_rows = (total + cols - 1) / cols grid_rows.times { lines << "" } # Pad remaining space while lines.size < oh - 3 lines << "" end # Footer lines << "" if total > 0 && items[sel_idx] lines << " :#{items[sel_idx][1]}:".fg(245) else lines << "" end .text = lines.join("\n") .ix = 0 .full_refresh .border_refresh # === Render emoji grid at explicit cursor positions === # This bypasses display_width entirely for grid alignment flat_i = 0 items.each_slice(cols) do |row| grid_row = flat_i / cols abs_row = oy + header_lines + grid_row row.each_with_index do |(emoji, _keyword), col_i| abs_col = ox + col_i * CELL_W STDOUT.print "\e[#{abs_row};#{abs_col}H" if flat_i == sel_idx STDOUT.print " #{emoji} ".c("236,255") # Inverted colors else STDOUT.print " #{emoji} ".c(fmt) end flat_i += 1 end end STDOUT.flush # Input chr = getchr(flush: false) case chr when 'ESC' return nil when 'ENTER' return (total > 0 && items[sel_idx]) ? items[sel_idx][0] : nil when 'RIGHT' sel_idx = [sel_idx + 1, total - 1].min if total > 0 when 'LEFT' sel_idx = [sel_idx - 1, 0].max when 'UP' sel_idx = [sel_idx - cols, 0].max when 'DOWN' sel_idx = [sel_idx + cols, total - 1].min if total > 0 when 'TAB' if search.empty? cat_idx = (cat_idx + 1) % categories.size sel_idx = 0 end when 'S-TAB' if search.empty? cat_idx = (cat_idx - 1) % categories.size sel_idx = 0 end when 'BACK' if search.length > 0 search = search[0..-2] sel_idx = 0 end when /^.$/ search << chr sel_idx = 0 end end ensure .cleanup if .respond_to?(:cleanup) end end |