melib/text_processing: add new wcwidth implementation
Download and parse Unicode data files to judge code point width. Inspired by https://github.com/ridiculousfish/widecharwidth/jmap-eventsource
parent
a7c0bca8ce
commit
1da6d75b08
318
melib/build.rs
318
melib/build.rs
|
@ -25,6 +25,9 @@ include!("src/text_processing/types.rs");
|
||||||
fn main() -> Result<(), std::io::Error> {
|
fn main() -> Result<(), std::io::Error> {
|
||||||
#[cfg(feature = "unicode_algorithms")]
|
#[cfg(feature = "unicode_algorithms")]
|
||||||
{
|
{
|
||||||
|
const MOD_PATH: &str = "src/text_processing/tables.rs";
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed={}", MOD_PATH);
|
||||||
/* Line break tables */
|
/* Line break tables */
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
@ -33,8 +36,15 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
const LINE_BREAK_TABLE_URL: &str =
|
const LINE_BREAK_TABLE_URL: &str =
|
||||||
"http://www.unicode.org/Public/UCD/latest/ucd/LineBreak.txt";
|
"http://www.unicode.org/Public/UCD/latest/ucd/LineBreak.txt";
|
||||||
|
/* Grapheme width tables */
|
||||||
|
const UNICODE_DATA_URL: &str =
|
||||||
|
"http://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt";
|
||||||
|
const EAW_URL: &str = "http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt";
|
||||||
|
const EMOJI_DATA_URL: &str =
|
||||||
|
"https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt";
|
||||||
|
|
||||||
let mod_path = Path::new("src/text_processing/tables.rs");
|
|
||||||
|
let mod_path = Path::new(MOD_PATH);
|
||||||
if mod_path.exists() {
|
if mod_path.exists() {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{} already exists, delete it if you want to replace it.",
|
"{} already exists, delete it if you want to replace it.",
|
||||||
|
@ -66,17 +76,255 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
let mut codepoint_iter = chars_str.split("..");
|
let mut codepoint_iter = chars_str.split("..");
|
||||||
|
|
||||||
let first_codepoint: u32 =
|
let first_codepoint: u32 =
|
||||||
u32::from_str_radix(std::dbg!(codepoint_iter.next().unwrap()), 16).unwrap();
|
u32::from_str_radix(codepoint_iter.next().unwrap(), 16).unwrap();
|
||||||
|
|
||||||
let sec_codepoint: u32 = codepoint_iter
|
let sec_codepoint: u32 = codepoint_iter
|
||||||
.next()
|
.next()
|
||||||
.map(|v| u32::from_str_radix(std::dbg!(v), 16).unwrap())
|
.map(|v| u32::from_str_radix(v, 16).unwrap())
|
||||||
.unwrap_or(first_codepoint);
|
.unwrap_or(first_codepoint);
|
||||||
let class = &tokens[semicolon_idx + 1..semicolon_idx + 1 + 2];
|
let class = &tokens[semicolon_idx + 1..semicolon_idx + 1 + 2];
|
||||||
line_break_table.push((first_codepoint, sec_codepoint, LineBreakClass::from(class)));
|
line_break_table.push((first_codepoint, sec_codepoint, LineBreakClass::from(class)));
|
||||||
}
|
}
|
||||||
child.wait()?;
|
child.wait()?;
|
||||||
|
|
||||||
|
let child = Command::new("curl")
|
||||||
|
.args(&["-o", "-", UNICODE_DATA_URL])
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
let unicode_data = String::from_utf8_lossy(&child.stdout);
|
||||||
|
|
||||||
|
let child = Command::new("curl")
|
||||||
|
.args(&["-o", "-", EAW_URL])
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
let eaw_data = String::from_utf8_lossy(&child.stdout);
|
||||||
|
|
||||||
|
let child = Command::new("curl")
|
||||||
|
.args(&["-o", "-", EMOJI_DATA_URL])
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
let emoji_data = String::from_utf8_lossy(&child.stdout);
|
||||||
|
|
||||||
|
const MAX_CODEPOINT: usize = 0x110000;
|
||||||
|
// See https://www.unicode.org/L2/L1999/UnicodeData.html
|
||||||
|
const FIELD_CODEPOINT: usize = 0;
|
||||||
|
const FIELD_CATEGORY: usize = 2;
|
||||||
|
// Ambiguous East Asian characters
|
||||||
|
const WIDTH_AMBIGUOUS_EASTASIAN: isize = -3;
|
||||||
|
|
||||||
|
// Width changed from 1 to 2 in Unicode 9.0
|
||||||
|
const WIDTH_WIDENED_IN_9: isize = -6;
|
||||||
|
// Category for unassigned codepoints.
|
||||||
|
const CAT_UNASSIGNED: &str = "Cn";
|
||||||
|
|
||||||
|
// Category for private use codepoints.
|
||||||
|
const CAT_PRIVATE_USE: &str = "Co";
|
||||||
|
|
||||||
|
// Category for surrogates.
|
||||||
|
const CAT_SURROGATE: &str = "Cs";
|
||||||
|
|
||||||
|
struct Codepoint<'cat> {
|
||||||
|
raw: u32,
|
||||||
|
width: Option<isize>,
|
||||||
|
category: &'cat str,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut codepoints: Vec<Codepoint> = Vec::with_capacity(MAX_CODEPOINT + 1);
|
||||||
|
for i in 0..=MAX_CODEPOINT {
|
||||||
|
codepoints.push(Codepoint {
|
||||||
|
raw: i as u32,
|
||||||
|
width: None,
|
||||||
|
category: CAT_UNASSIGNED,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
set_general_categories(&mut codepoints, &unicode_data);
|
||||||
|
set_eaw_widths(&mut codepoints, &eaw_data);
|
||||||
|
set_emoji_widths(&mut codepoints, &emoji_data);
|
||||||
|
set_hardcoded_ranges(&mut codepoints);
|
||||||
|
fn hexrange_to_range(hexrange: &str) -> std::ops::Range<usize> {
|
||||||
|
/* Given a string like 1F300..1F320 representing an inclusive range,
|
||||||
|
return the range of codepoints.
|
||||||
|
If the string is like 1F321, return a range of just that element.
|
||||||
|
*/
|
||||||
|
let hexrange = hexrange.trim();
|
||||||
|
let fields = hexrange
|
||||||
|
.split("..")
|
||||||
|
.map(|h| usize::from_str_radix(h.trim(), 16).unwrap())
|
||||||
|
.collect::<Vec<usize>>();
|
||||||
|
if fields.len() == 1 {
|
||||||
|
fields[0]..(fields[0] + 1)
|
||||||
|
} else {
|
||||||
|
fields[0]..(fields[1] + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_general_categories<'u>(codepoints: &mut Vec<Codepoint<'u>>, unicode_data: &'u str) {
|
||||||
|
for line in unicode_data.lines() {
|
||||||
|
let fields = line.trim().split(";").collect::<Vec<_>>();
|
||||||
|
if fields.len() > FIELD_CATEGORY {
|
||||||
|
for idx in hexrange_to_range(fields[FIELD_CODEPOINT]) {
|
||||||
|
codepoints[idx].category = fields[FIELD_CATEGORY];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_eaw_widths(codepoints: &mut Vec<Codepoint<'_>>, eaw_data_lines: &str) {
|
||||||
|
// Read from EastAsianWidth.txt, set width values on the codepoints
|
||||||
|
for line in eaw_data_lines.lines() {
|
||||||
|
let line = line.trim().split('#').next().unwrap_or(line);
|
||||||
|
let fields = line.trim().split(';').collect::<Vec<_>>();
|
||||||
|
if fields.len() != 2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let hexrange = fields[0];
|
||||||
|
let width_type = fields[1];
|
||||||
|
// width_types:
|
||||||
|
// A: ambiguous, F: fullwidth, H: halfwidth,
|
||||||
|
// . N: neutral, Na: east-asian Narrow
|
||||||
|
let width: isize = if width_type == "A" {
|
||||||
|
WIDTH_AMBIGUOUS_EASTASIAN
|
||||||
|
} else if width_type == "F" || width_type == "W" {
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
for cp in hexrange_to_range(hexrange) {
|
||||||
|
codepoints[cp].width = Some(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Apply the following special cases:
|
||||||
|
// - The unassigned code points in the following blocks default to "W":
|
||||||
|
// CJK Unified Ideographs Extension A: U+3400..U+4DBF
|
||||||
|
// CJK Unified Ideographs: U+4E00..U+9FFF
|
||||||
|
// CJK Compatibility Ideographs: U+F900..U+FAFF
|
||||||
|
// - All undesignated code points in Planes 2 and 3, whether inside or
|
||||||
|
// outside of allocated blocks, default to "W":
|
||||||
|
// Plane 2: U+20000..U+2FFFD
|
||||||
|
// Plane 3: U+30000..U+3FFFD
|
||||||
|
const WIDE_RANGES: [(usize, usize); 5] = [
|
||||||
|
(0x3400, 0x4DBF),
|
||||||
|
(0x4E00, 0x9FFF),
|
||||||
|
(0xF900, 0xFAFF),
|
||||||
|
(0x20000, 0x2FFFD),
|
||||||
|
(0x30000, 0x3FFFD),
|
||||||
|
];
|
||||||
|
for &wr in WIDE_RANGES.iter() {
|
||||||
|
for cp in wr.0..(wr.1 + 1) {
|
||||||
|
if codepoints[cp].width.is_none() {
|
||||||
|
codepoints[cp].width = Some(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn set_emoji_widths(codepoints: &mut Vec<Codepoint<'_>>, emoji_data_lines: &str) {
|
||||||
|
// Read from emoji-data.txt, set codepoint widths
|
||||||
|
for line in emoji_data_lines.lines() {
|
||||||
|
if !line.contains("#") || line.trim().starts_with("#") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut fields = line.trim().split('#').collect::<Vec<_>>();
|
||||||
|
if fields.len() != 2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let comment = fields.pop().unwrap();
|
||||||
|
let fields = fields.pop().unwrap();
|
||||||
|
|
||||||
|
let hexrange = fields.split(";").next().unwrap();
|
||||||
|
|
||||||
|
// In later versions of emoji-data.txt there are some "reserved"
|
||||||
|
// entries that have "NA" instead of a Unicode version number
|
||||||
|
// of first use, they will now return a zero version instead of
|
||||||
|
// crashing the script
|
||||||
|
if comment.trim().starts_with("NA") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
let mut v = comment.trim().split_whitespace().next().unwrap();
|
||||||
|
if v.starts_with("E") {
|
||||||
|
v = &v[1..];
|
||||||
|
}
|
||||||
|
if v.as_bytes()
|
||||||
|
.get(0)
|
||||||
|
.map(|c| !c.is_ascii_digit())
|
||||||
|
.unwrap_or(true)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut idx = 1;
|
||||||
|
while v
|
||||||
|
.as_bytes()
|
||||||
|
.get(idx)
|
||||||
|
.map(|c| c.is_ascii_digit())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
if v.as_bytes().get(idx).map(|&c| c != b'.').unwrap_or(true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
idx += 1;
|
||||||
|
while v
|
||||||
|
.as_bytes()
|
||||||
|
.get(idx)
|
||||||
|
.map(|c| c.is_ascii_digit())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
v = &v[0..idx];
|
||||||
|
|
||||||
|
let version = f32::from_str(v).unwrap();
|
||||||
|
for cp in hexrange_to_range(hexrange) {
|
||||||
|
// Don't consider <=1F000 values as emoji. These can only be made
|
||||||
|
// emoji through the variation selector which interacts terribly
|
||||||
|
// with wcwidth().
|
||||||
|
if cp < 0x1F000 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Skip codepoints that are explicitly not wide.
|
||||||
|
// For example U+1F336 ("Hot Pepper") renders like any emoji but is
|
||||||
|
// marked as neutral in EAW so has width 1 for some reason.
|
||||||
|
//if codepoints[cp].width == Some(1) {
|
||||||
|
// continue;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// If this emoji was introduced before Unicode 9, then it was widened in 9.
|
||||||
|
codepoints[cp].width = if version >= 9.0 {
|
||||||
|
Some(2)
|
||||||
|
} else {
|
||||||
|
Some(WIDTH_WIDENED_IN_9)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn set_hardcoded_ranges(codepoints: &mut Vec<Codepoint<'_>>) {
|
||||||
|
// Mark private use and surrogate codepoints
|
||||||
|
// Private use can be determined awkwardly from UnicodeData.txt,
|
||||||
|
// but we just hard-code them.
|
||||||
|
// We do not treat "private use high surrogate" as private use
|
||||||
|
// so as to match wcwidth9().
|
||||||
|
const PRIVATE_RANGES: [(usize, usize); 3] =
|
||||||
|
[(0xE000, 0xF8FF), (0xF0000, 0xFFFFD), (0x100000, 0x10FFFD)];
|
||||||
|
for &(first, last) in PRIVATE_RANGES.iter() {
|
||||||
|
for idx in first..=last {
|
||||||
|
codepoints[idx].category = CAT_PRIVATE_USE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SURROGATE_RANGES: [(usize, usize); 2] = [(0xD800, 0xDBFF), (0xDC00, 0xDFFF)];
|
||||||
|
for &(first, last) in SURROGATE_RANGES.iter() {
|
||||||
|
for idx in first..=last {
|
||||||
|
codepoints[idx].category = CAT_SURROGATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut file = File::create(&mod_path)?;
|
let mut file = File::create(&mod_path)?;
|
||||||
file.write_all(
|
file.write_all(
|
||||||
br#"/*
|
br#"/*
|
||||||
|
@ -110,7 +358,69 @@ pub const LINE_BREAK_RULES: &[(u32, u32, LineBreakClass)] = &[
|
||||||
file.write_all(format!(" (0x{:X}, 0x{:X}, {:?}),\n", l.0, l.1, l.2).as_bytes())
|
file.write_all(format!(" (0x{:X}, 0x{:X}, {:?}),\n", l.0, l.1, l.2).as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
file.write_all(b"];").unwrap();
|
file.write_all(b"];\n").unwrap();
|
||||||
|
|
||||||
|
for (name, filter) in [
|
||||||
|
(
|
||||||
|
"ASCII",
|
||||||
|
Box::new(|c: &&Codepoint| c.raw < 0x7f && c.raw >= 0x20)
|
||||||
|
as Box<dyn Fn(&&Codepoint) -> bool>,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"PRIVATE",
|
||||||
|
Box::new(|c: &&Codepoint| c.category == CAT_PRIVATE_USE),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"NONPRINT",
|
||||||
|
Box::new(|c: &&Codepoint| {
|
||||||
|
["Cc", "Cf", "Zl", "Zp", CAT_SURROGATE].contains(&c.category)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"COMBINING",
|
||||||
|
Box::new(|c: &&Codepoint| ["Mn", "Mc", "Me"].contains(&c.category)),
|
||||||
|
),
|
||||||
|
("DOUBLEWIDE", Box::new(|c: &&Codepoint| c.width == Some(2))),
|
||||||
|
(
|
||||||
|
"UNASSIGNED",
|
||||||
|
Box::new(|c: &&Codepoint| c.category == CAT_UNASSIGNED),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"AMBIGUOUS",
|
||||||
|
Box::new(|c: &&Codepoint| c.width == Some(WIDTH_AMBIGUOUS_EASTASIAN)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"WIDENEDIN9",
|
||||||
|
Box::new(|c: &&Codepoint| c.width == Some(WIDTH_WIDENED_IN_9)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
{
|
||||||
|
file.write_all(
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
pub const {}: &[(u32, u32)] = &[
|
||||||
|
"#,
|
||||||
|
name
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut iter = codepoints.iter().filter(filter);
|
||||||
|
let mut prev = iter.next().unwrap().raw;
|
||||||
|
let mut a = prev;
|
||||||
|
for cp in iter {
|
||||||
|
if prev + 1 != cp.raw {
|
||||||
|
file.write_all(format!(" (0x{:X}, 0x{:X}),\n", a, prev).as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
a = cp.raw;
|
||||||
|
}
|
||||||
|
prev = cp.raw;
|
||||||
|
}
|
||||||
|
file.write_all(format!(" (0x{:X}, 0x{:X}),\n", a, prev).as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
file.write_all(b"];\n").unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -136,174 +136,36 @@ fn bisearch(ucs: WChar, table: &'static [Interval]) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The following functions define the column width of an ISO 10646
|
|
||||||
* character as follows:
|
|
||||||
*
|
|
||||||
* - The null character (U+0000) has a column width of 0.
|
|
||||||
*
|
|
||||||
* - Other C0/C1 control characters and DEL will lead to a return
|
|
||||||
* value of -1.
|
|
||||||
*
|
|
||||||
* - Non-spacing and enclosing combining characters (general
|
|
||||||
* category code Mn or Me in the Unicode database) have a
|
|
||||||
* column width of 0.
|
|
||||||
*
|
|
||||||
* - Other format characters (general category code Cf in the Unicode
|
|
||||||
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
|
|
||||||
*
|
|
||||||
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
|
|
||||||
* have a column width of 0.
|
|
||||||
*
|
|
||||||
* - Spacing characters in the East Asian Wide (W) or East Asian
|
|
||||||
* FullWidth (F) category as defined in Unicode Technical
|
|
||||||
* Report #11 have a column width of 2.
|
|
||||||
*
|
|
||||||
* - All remaining characters (including all printable
|
|
||||||
* ISO 8859-1 and WGL4 characters, Unicode control characters,
|
|
||||||
* etc.) have a column width of 1.
|
|
||||||
*
|
|
||||||
* This implementation assumes that wchar_t characters are encoded
|
|
||||||
* in ISO 10646.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub fn wcwidth(ucs: WChar) -> Option<usize> {
|
pub fn wcwidth(ucs: WChar) -> Option<usize> {
|
||||||
/* sorted list of non-overlapping intervals of non-spacing characters */
|
if bisearch(ucs, super::tables::ASCII) {
|
||||||
const COMBINING: &[Interval] = &[
|
Some(1)
|
||||||
(0x0300, 0x034E),
|
} else if bisearch(ucs, super::tables::PRIVATE) {
|
||||||
(0x0360, 0x0362),
|
None
|
||||||
(0x0483, 0x0486),
|
} else if bisearch(ucs, super::tables::NONPRINT) {
|
||||||
(0x0488, 0x0489),
|
None
|
||||||
(0x0591, 0x05A1),
|
} else if bisearch(ucs, super::tables::COMBINING) {
|
||||||
(0x05A3, 0x05B9),
|
None
|
||||||
(0x05BB, 0x05BD),
|
} else if bisearch(ucs, super::tables::DOUBLEWIDE) {
|
||||||
(0x05BF, 0x05BF),
|
Some(2)
|
||||||
(0x05C1, 0x05C2),
|
} else if bisearch(ucs, super::tables::AMBIGUOUS) {
|
||||||
(0x05C4, 0x05C4),
|
Some(1)
|
||||||
(0x064B, 0x0655),
|
} else if bisearch(ucs, super::tables::UNASSIGNED) {
|
||||||
(0x0670, 0x0670),
|
Some(2)
|
||||||
(0x06D6, 0x06E4),
|
} else if bisearch(ucs, super::tables::WIDENEDIN9) {
|
||||||
(0x06E7, 0x06E8),
|
Some(2)
|
||||||
(0x06EA, 0x06ED),
|
} else {
|
||||||
(0x070F, 0x070F),
|
Some(1)
|
||||||
(0x0711, 0x0711),
|
|
||||||
(0x0730, 0x074A),
|
|
||||||
(0x07A6, 0x07B0),
|
|
||||||
(0x0901, 0x0902),
|
|
||||||
(0x093C, 0x093C),
|
|
||||||
(0x0941, 0x0948),
|
|
||||||
(0x094D, 0x094D),
|
|
||||||
(0x0951, 0x0954),
|
|
||||||
(0x0962, 0x0963),
|
|
||||||
(0x0981, 0x0981),
|
|
||||||
(0x09BC, 0x09BC),
|
|
||||||
(0x09C1, 0x09C4),
|
|
||||||
(0x09CD, 0x09CD),
|
|
||||||
(0x09E2, 0x09E3),
|
|
||||||
(0x0A02, 0x0A02),
|
|
||||||
(0x0A3C, 0x0A3C),
|
|
||||||
(0x0A41, 0x0A42),
|
|
||||||
(0x0A47, 0x0A48),
|
|
||||||
(0x0A4B, 0x0A4D),
|
|
||||||
(0x0A70, 0x0A71),
|
|
||||||
(0x0A81, 0x0A82),
|
|
||||||
(0x0ABC, 0x0ABC),
|
|
||||||
(0x0AC1, 0x0AC5),
|
|
||||||
(0x0AC7, 0x0AC8),
|
|
||||||
(0x0ACD, 0x0ACD),
|
|
||||||
(0x0B01, 0x0B01),
|
|
||||||
(0x0B3C, 0x0B3C),
|
|
||||||
(0x0B3F, 0x0B3F),
|
|
||||||
(0x0B41, 0x0B43),
|
|
||||||
(0x0B4D, 0x0B4D),
|
|
||||||
(0x0B56, 0x0B56),
|
|
||||||
(0x0B82, 0x0B82),
|
|
||||||
(0x0BC0, 0x0BC0),
|
|
||||||
(0x0BCD, 0x0BCD),
|
|
||||||
(0x0C3E, 0x0C40),
|
|
||||||
(0x0C46, 0x0C48),
|
|
||||||
(0x0C4A, 0x0C4D),
|
|
||||||
(0x0C55, 0x0C56),
|
|
||||||
(0x0CBF, 0x0CBF),
|
|
||||||
(0x0CC6, 0x0CC6),
|
|
||||||
(0x0CCC, 0x0CCD),
|
|
||||||
(0x0D41, 0x0D43),
|
|
||||||
(0x0D4D, 0x0D4D),
|
|
||||||
(0x0DCA, 0x0DCA),
|
|
||||||
(0x0DD2, 0x0DD4),
|
|
||||||
(0x0DD6, 0x0DD6),
|
|
||||||
(0x0E31, 0x0E31),
|
|
||||||
(0x0E34, 0x0E3A),
|
|
||||||
(0x0E47, 0x0E4E),
|
|
||||||
(0x0EB1, 0x0EB1),
|
|
||||||
(0x0EB4, 0x0EB9),
|
|
||||||
(0x0EBB, 0x0EBC),
|
|
||||||
(0x0EC8, 0x0ECD),
|
|
||||||
(0x0F18, 0x0F19),
|
|
||||||
(0x0F35, 0x0F35),
|
|
||||||
(0x0F37, 0x0F37),
|
|
||||||
(0x0F39, 0x0F39),
|
|
||||||
(0x0F71, 0x0F7E),
|
|
||||||
(0x0F80, 0x0F84),
|
|
||||||
(0x0F86, 0x0F87),
|
|
||||||
(0x0F90, 0x0F97),
|
|
||||||
(0x0F99, 0x0FBC),
|
|
||||||
(0x0FC6, 0x0FC6),
|
|
||||||
(0x102D, 0x1030),
|
|
||||||
(0x1032, 0x1032),
|
|
||||||
(0x1036, 0x1037),
|
|
||||||
(0x1039, 0x1039),
|
|
||||||
(0x1058, 0x1059),
|
|
||||||
(0x1160, 0x11FF),
|
|
||||||
(0x17B7, 0x17BD),
|
|
||||||
(0x17C6, 0x17C6),
|
|
||||||
(0x17C9, 0x17D3),
|
|
||||||
(0x180B, 0x180E),
|
|
||||||
(0x18A9, 0x18A9),
|
|
||||||
(0x200B, 0x200F),
|
|
||||||
(0x202A, 0x202E),
|
|
||||||
(0x206A, 0x206F),
|
|
||||||
(0x20D0, 0x20E3),
|
|
||||||
(0x302A, 0x302F),
|
|
||||||
(0x3099, 0x309A),
|
|
||||||
(0xFB1E, 0xFB1E),
|
|
||||||
(0xFE20, 0xFE23),
|
|
||||||
(0xFEFF, 0xFEFF),
|
|
||||||
(0xFFF9, 0xFFFB),
|
|
||||||
];
|
|
||||||
|
|
||||||
/* test for 8-bit control characters */
|
|
||||||
if ucs == 0 {
|
|
||||||
return Some(0);
|
|
||||||
}
|
|
||||||
if ucs < 32 || (ucs >= 0x7f && ucs < 0xa0) {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* binary search in table of emojis */
|
#[test]
|
||||||
if bisearch(ucs, EMOJI_RANGES) {
|
fn test_wcwidth() {
|
||||||
return Some(2);
|
use crate::text_processing::grapheme_clusters::TextProcessing;
|
||||||
}
|
assert_eq!("●".grapheme_width(), 1);
|
||||||
/* binary search in table of non-spacing characters */
|
assert_eq!("●📎".grapheme_width(), 3);
|
||||||
if bisearch(ucs, COMBINING) {
|
assert_eq!("●\u{FE0E}📎\u{FE0E}".grapheme_width(), 3);
|
||||||
return Some(1);
|
assert_eq!("🎃".grapheme_width(), 2);
|
||||||
}
|
assert_eq!("👻".grapheme_width(), 2);
|
||||||
|
|
||||||
/* if we arrive here, ucs is not a combining or C0/C1 control character */
|
|
||||||
|
|
||||||
Some(
|
|
||||||
1 + big_if_true!(
|
|
||||||
ucs >= 0x1100
|
|
||||||
&& (ucs <= 0x115f || /* Hangul Jamo init. consonants */
|
|
||||||
(ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & !0x0011) != 0x300a &&
|
|
||||||
ucs != 0x303f) || /* CJK ... Yi */
|
|
||||||
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
|
|
||||||
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
|
|
||||||
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
|
|
||||||
(ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
|
|
||||||
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
|
|
||||||
(ucs >= 0x20000 && ucs <= 0x2ffff))
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wcswidth(mut pwcs: WChar, mut n: usize) -> Option<usize> {
|
pub fn wcswidth(mut pwcs: WChar, mut n: usize) -> Option<usize> {
|
||||||
|
@ -322,360 +184,3 @@ pub fn wcswidth(mut pwcs: WChar, mut n: usize) -> Option<usize> {
|
||||||
|
|
||||||
Some(width)
|
Some(width)
|
||||||
}
|
}
|
||||||
|
|
||||||
const EMOJI_RANGES: &[Interval] = &[
|
|
||||||
(0x231A, 0x231B), // ; Basic_Emoji ; watch # 1.1 [2] (⌚..⌛)
|
|
||||||
(0x23E9, 0x23EC), // ; Basic_Emoji ; fast-forward button # 6.0 [4] (⏩..⏬)
|
|
||||||
(0x23F0, 0x23F0), // ; Basic_Emoji ; alarm clock # 6.0 [1] (⏰)
|
|
||||||
(0x23F3, 0x23F3), // ; Basic_Emoji ; hourglass not done # 6.0 [1] (⏳)
|
|
||||||
(0x25FD, 0x25FE), // ; Basic_Emoji ; white medium-small square # 3.2 [2] (◽..◾)
|
|
||||||
(0x2614, 0x2615), // ; Basic_Emoji ; umbrella with rain drops # 4.0 [2] (☔..☕)
|
|
||||||
(0x2648, 0x2653), // ; Basic_Emoji ; Aries # 1.1 [12] (♈..♓)
|
|
||||||
(0x267F, 0x267F), // ; Basic_Emoji ; wheelchair symbol # 4.1 [1] (♿)
|
|
||||||
(0x2693, 0x2693), // ; Basic_Emoji ; anchor # 4.1 [1] (⚓)
|
|
||||||
(0x26A1, 0x26A1), // ; Basic_Emoji ; high voltage # 4.0 [1] (⚡)
|
|
||||||
(0x26AA, 0x26AB), // ; Basic_Emoji ; white circle # 4.1 [2] (⚪..⚫)
|
|
||||||
(0x26BD, 0x26BE), // ; Basic_Emoji ; soccer ball # 5.2 [2] (⚽..⚾)
|
|
||||||
(0x26C4, 0x26C5), // ; Basic_Emoji ; snowman without snow # 5.2 [2] (⛄..⛅)
|
|
||||||
(0x26CE, 0x26CE), // ; Basic_Emoji ; Ophiuchus # 6.0 [1] (⛎)
|
|
||||||
(0x26D4, 0x26D4), // ; Basic_Emoji ; no entry # 5.2 [1] (⛔)
|
|
||||||
(0x26EA, 0x26EA), // ; Basic_Emoji ; church # 5.2 [1] (⛪)
|
|
||||||
(0x26F2, 0x26F3), // ; Basic_Emoji ; fountain # 5.2 [2] (⛲..⛳)
|
|
||||||
(0x26F5, 0x26F5), // ; Basic_Emoji ; sailboat # 5.2 [1] (⛵)
|
|
||||||
(0x26FA, 0x26FA), // ; Basic_Emoji ; tent # 5.2 [1] (⛺)
|
|
||||||
(0x26FD, 0x26FD), // ; Basic_Emoji ; fuel pump # 5.2 [1] (⛽)
|
|
||||||
(0x2705, 0x2705), // ; Basic_Emoji ; check mark button # 6.0 [1] (✅)
|
|
||||||
(0x270A, 0x270B), // ; Basic_Emoji ; raised fist # 6.0 [2] (✊..✋)
|
|
||||||
(0x2728, 0x2728), // ; Basic_Emoji ; sparkles # 6.0 [1] (✨)
|
|
||||||
(0x274C, 0x274C), // ; Basic_Emoji ; cross mark # 6.0 [1] (❌)
|
|
||||||
(0x274E, 0x274E), // ; Basic_Emoji ; cross mark button # 6.0 [1] (❎)
|
|
||||||
(0x2753, 0x2755), // ; Basic_Emoji ; question mark # 6.0 [3] (❓..❕)
|
|
||||||
(0x2757, 0x2757), // ; Basic_Emoji ; exclamation mark # 5.2 [1] (❗)
|
|
||||||
(0x2795, 0x2797), // ; Basic_Emoji ; plus sign # 6.0 [3] (➕..➗)
|
|
||||||
(0x27B0, 0x27B0), // ; Basic_Emoji ; curly loop # 6.0 [1] (➰)
|
|
||||||
(0x27BF, 0x27BF), // ; Basic_Emoji ; double curly loop # 6.0 [1] (➿)
|
|
||||||
(0x2B1B, 0x2B1C), // ; Basic_Emoji ; black large square # 5.1 [2] (⬛..⬜)
|
|
||||||
(0x2B50, 0x2B50), // ; Basic_Emoji ; star # 5.1 [1] (⭐)
|
|
||||||
(0x2B55, 0x2B55), // ; Basic_Emoji ; hollow red circle # 5.2 [1] (⭕)
|
|
||||||
(0x1F004, 0x1F004), // ; Basic_Emoji ; mahjong red dragon # 5.1 [1] (🀄)
|
|
||||||
(0x1F0CF, 0x1F0CF), // ; Basic_Emoji ; joker # 6.0 [1] (🃏)
|
|
||||||
(0x1F18E, 0x1F18E), // ; Basic_Emoji ; AB button (blood type) # 6.0 [1] (🆎)
|
|
||||||
(0x1F191, 0x1F19A), // ; Basic_Emoji ; CL button # 6.0 [10] (🆑..🆚)
|
|
||||||
(0x1F201, 0x1F201), // ; Basic_Emoji ; Japanese “here” button # 6.0 [1] (🈁)
|
|
||||||
(0x1F21A, 0x1F21A), // ; Basic_Emoji ; Japanese “free of charge” button # 5.2 [1] (🈚)
|
|
||||||
(0x1F22F, 0x1F22F), // ; Basic_Emoji ; Japanese “reserved” button # 5.2 [1] (🈯)
|
|
||||||
(0x1F232, 0x1F236), // ; Basic_Emoji ; Japanese “prohibited” button # 6.0 [5] (🈲..🈶)
|
|
||||||
(0x1F238, 0x1F23A), // ; Basic_Emoji ; Japanese “application” button # 6.0 [3] (🈸..🈺)
|
|
||||||
(0x1F250, 0x1F251), // ; Basic_Emoji ; Japanese “bargain” button # 6.0 [2] (🉐..🉑)
|
|
||||||
(0x1F300, 0x1F320), // ; Basic_Emoji ; cyclone # 6.0 [33] (🌀..🌠)
|
|
||||||
(0x1F32D, 0x1F32F), // ; Basic_Emoji ; hot dog # 8.0 [3] (🌭..🌯)
|
|
||||||
(0x1F330, 0x1F335), // ; Basic_Emoji ; chestnut # 6.0 [6] (🌰..🌵)
|
|
||||||
(0x1F337, 0x1F37C), // ; Basic_Emoji ; tulip # 6.0 [70] (🌷..🍼)
|
|
||||||
(0x1F37E, 0x1F37F), // ; Basic_Emoji ; bottle with popping cork # 8.0 [2] (🍾..🍿)
|
|
||||||
(0x1F380, 0x1F393), // ; Basic_Emoji ; ribbon # 6.0 [20] (🎀..🎓)
|
|
||||||
(0x1F3A0, 0x1F3C4), // ; Basic_Emoji ; carousel horse # 6.0 [37] (🎠..🏄)
|
|
||||||
(0x1F3C5, 0x1F3C5), // ; Basic_Emoji ; sports medal # 7.0 [1] (🏅)
|
|
||||||
(0x1F3C6, 0x1F3CA), // ; Basic_Emoji ; trophy # 6.0 [5] (🏆..🏊)
|
|
||||||
(0x1F3CF, 0x1F3D3), // ; Basic_Emoji ; cricket game # 8.0 [5] (🏏..🏓)
|
|
||||||
(0x1F3E0, 0x1F3F0), // ; Basic_Emoji ; house # 6.0 [17] (🏠..🏰)
|
|
||||||
(0x1F3F4, 0x1F3F4), // ; Basic_Emoji ; black flag # 7.0 [1] (🏴)
|
|
||||||
(0x1F3F8, 0x1F3FF), // ; Basic_Emoji ; badminton # 8.0 [8] (🏸..🏿)
|
|
||||||
(0x1F400, 0x1F43E), // ; Basic_Emoji ; rat # 6.0 [63] (🐀..🐾)
|
|
||||||
(0x1F440, 0x1F440), // ; Basic_Emoji ; eyes # 6.0 [1] (👀)
|
|
||||||
(0x1F442, 0x1F4F7), // ; Basic_Emoji ; ear # 6.0[182] (👂..📷)
|
|
||||||
(0x1F4F8, 0x1F4F8), // ; Basic_Emoji ; camera with flash # 7.0 [1] (📸)
|
|
||||||
(0x1F4F9, 0x1F4FC), // ; Basic_Emoji ; video camera # 6.0 [4] (📹..📼)
|
|
||||||
(0x1F4FF, 0x1F4FF), // ; Basic_Emoji ; prayer beads # 8.0 [1] (📿)
|
|
||||||
(0x1F500, 0x1F53D), // ; Basic_Emoji ; shuffle tracks button # 6.0 [62] (🔀..🔽)
|
|
||||||
(0x1F54B, 0x1F54E), // ; Basic_Emoji ; kaaba # 8.0 [4] (🕋..🕎)
|
|
||||||
(0x1F550, 0x1F567), // ; Basic_Emoji ; one o’clock # 6.0 [24] (🕐..🕧)
|
|
||||||
(0x1F57A, 0x1F57A), // ; Basic_Emoji ; man dancing # 9.0 [1] (🕺)
|
|
||||||
(0x1F595, 0x1F596), // ; Basic_Emoji ; middle finger # 7.0 [2] (🖕..🖖)
|
|
||||||
(0x1F5A4, 0x1F5A4), // ; Basic_Emoji ; black heart # 9.0 [1] (🖤)
|
|
||||||
(0x1F5FB, 0x1F5FF), // ; Basic_Emoji ; mount fuji # 6.0 [5] (🗻..🗿)
|
|
||||||
(0x1F600, 0x1F600), // ; Basic_Emoji ; grinning face # 6.1 [1] (😀)
|
|
||||||
(0x1F601, 0x1F610), // ; Basic_Emoji ; beaming face with smiling eyes # 6.0 [16] (😁..😐)
|
|
||||||
(0x1F611, 0x1F611), // ; Basic_Emoji ; expressionless face # 6.1 [1] (😑)
|
|
||||||
(0x1F612, 0x1F614), // ; Basic_Emoji ; unamused face # 6.0 [3] (😒..😔)
|
|
||||||
(0x1F615, 0x1F615), // ; Basic_Emoji ; confused face # 6.1 [1] (😕)
|
|
||||||
(0x1F616, 0x1F616), // ; Basic_Emoji ; confounded face # 6.0 [1] (😖)
|
|
||||||
(0x1F617, 0x1F617), // ; Basic_Emoji ; kissing face # 6.1 [1] (😗)
|
|
||||||
(0x1F618, 0x1F618), // ; Basic_Emoji ; face blowing a kiss # 6.0 [1] (😘)
|
|
||||||
(0x1F619, 0x1F619), // ; Basic_Emoji ; kissing face with smiling eyes # 6.1 [1] (😙)
|
|
||||||
(0x1F61A, 0x1F61A), // ; Basic_Emoji ; kissing face with closed eyes # 6.0 [1] (😚)
|
|
||||||
(0x1F61B, 0x1F61B), // ; Basic_Emoji ; face with tongue # 6.1 [1] (😛)
|
|
||||||
(0x1F61C, 0x1F61E), // ; Basic_Emoji ; winking face with tongue # 6.0 [3] (😜..😞)
|
|
||||||
(0x1F61F, 0x1F61F), // ; Basic_Emoji ; worried face # 6.1 [1] (😟)
|
|
||||||
(0x1F620, 0x1F625), // ; Basic_Emoji ; angry face # 6.0 [6] (😠..😥)
|
|
||||||
(0x1F626, 0x1F627), // ; Basic_Emoji ; frowning face with open mouth # 6.1 [2] (😦..😧)
|
|
||||||
(0x1F628, 0x1F62B), // ; Basic_Emoji ; fearful face # 6.0 [4] (😨..😫)
|
|
||||||
(0x1F62C, 0x1F62C), // ; Basic_Emoji ; grimacing face # 6.1 [1] (😬)
|
|
||||||
(0x1F62D, 0x1F62D), // ; Basic_Emoji ; loudly crying face # 6.0 [1] (😭)
|
|
||||||
(0x1F62E, 0x1F62F), // ; Basic_Emoji ; face with open mouth # 6.1 [2] (😮..😯)
|
|
||||||
(0x1F630, 0x1F633), // ; Basic_Emoji ; anxious face with sweat # 6.0 [4] (😰..😳)
|
|
||||||
(0x1F634, 0x1F634), // ; Basic_Emoji ; sleeping face # 6.1 [1] (😴)
|
|
||||||
(0x1F635, 0x1F640), // ; Basic_Emoji ; dizzy face # 6.0 [12] (😵..🙀)
|
|
||||||
(0x1F641, 0x1F642), // ; Basic_Emoji ; slightly frowning face # 7.0 [2] (🙁..🙂)
|
|
||||||
(0x1F643, 0x1F644), // ; Basic_Emoji ; upside-down face # 8.0 [2] (🙃..🙄)
|
|
||||||
(0x1F645, 0x1F64F), // ; Basic_Emoji ; person gesturing NO # 6.0 [11] (🙅..🙏)
|
|
||||||
(0x1F680, 0x1F6C5), // ; Basic_Emoji ; rocket # 6.0 [70] (🚀..🛅)
|
|
||||||
(0x1F6CC, 0x1F6CC), // ; Basic_Emoji ; person in bed # 7.0 [1] (🛌)
|
|
||||||
(0x1F6D0, 0x1F6D0), // ; Basic_Emoji ; place of worship # 8.0 [1] (🛐)
|
|
||||||
(0x1F6D1, 0x1F6D2), // ; Basic_Emoji ; stop sign # 9.0 [2] (🛑..🛒)
|
|
||||||
(0x1F6D5, 0x1F6D5), // ; Basic_Emoji ; hindu temple # 12.0 [1] (🛕)
|
|
||||||
(0x1F6EB, 0x1F6EC), // ; Basic_Emoji ; airplane departure # 7.0 [2] (🛫..🛬)
|
|
||||||
(0x1F6F4, 0x1F6F6), // ; Basic_Emoji ; kick scooter # 9.0 [3] (🛴..🛶)
|
|
||||||
(0x1F6F7, 0x1F6F8), // ; Basic_Emoji ; sled # 10.0 [2] (🛷..🛸)
|
|
||||||
(0x1F6F9, 0x1F6F9), // ; Basic_Emoji ; skateboard # 11.0 [1] (🛹)
|
|
||||||
(0x1F6FA, 0x1F6FA), // ; Basic_Emoji ; auto rickshaw # 12.0 [1] (🛺)
|
|
||||||
(0x1F7E0, 0x1F7EB), // ; Basic_Emoji ; orange circle # 12.0 [12] (🟠..🟫)
|
|
||||||
(0x1F90D, 0x1F90F), // ; Basic_Emoji ; white heart # 12.0 [3] (🤍..🤏)
|
|
||||||
(0x1F910, 0x1F918), // ; Basic_Emoji ; zipper-mouth face # 8.0 [9] (🤐..🤘)
|
|
||||||
(0x1F919, 0x1F91E), // ; Basic_Emoji ; call me hand # 9.0 [6] (🤙..🤞)
|
|
||||||
(0x1F91F, 0x1F91F), // ; Basic_Emoji ; love-you gesture # 10.0 [1] (🤟)
|
|
||||||
(0x1F920, 0x1F927), // ; Basic_Emoji ; cowboy hat face # 9.0 [8] (🤠..🤧)
|
|
||||||
(0x1F928, 0x1F92F), // ; Basic_Emoji ; face with raised eyebrow # 10.0 [8] (🤨..🤯)
|
|
||||||
(0x1F930, 0x1F930), // ; Basic_Emoji ; pregnant woman # 9.0 [1] (🤰)
|
|
||||||
(0x1F931, 0x1F932), // ; Basic_Emoji ; breast-feeding # 10.0 [2] (🤱..🤲)
|
|
||||||
(0x1F933, 0x1F93A), // ; Basic_Emoji ; selfie # 9.0 [8] (🤳..🤺)
|
|
||||||
(0x1F93C, 0x1F93E), // ; Basic_Emoji ; people wrestling # 9.0 [3] (🤼..🤾)
|
|
||||||
(0x1F93F, 0x1F93F), // ; Basic_Emoji ; diving mask # 12.0 [1] (🤿)
|
|
||||||
(0x1F940, 0x1F945), // ; Basic_Emoji ; wilted flower # 9.0 [6] (🥀..🥅)
|
|
||||||
(0x1F947, 0x1F94B), // ; Basic_Emoji ; 1st place medal # 9.0 [5] (🥇..🥋)
|
|
||||||
(0x1F94C, 0x1F94C), // ; Basic_Emoji ; curling stone # 10.0 [1] (🥌)
|
|
||||||
(0x1F94D, 0x1F94F), // ; Basic_Emoji ; lacrosse # 11.0 [3] (🥍..🥏)
|
|
||||||
(0x1F950, 0x1F95E), // ; Basic_Emoji ; croissant # 9.0 [15] (🥐..🥞)
|
|
||||||
(0x1F95F, 0x1F96B), // ; Basic_Emoji ; dumpling # 10.0 [13] (🥟..🥫)
|
|
||||||
(0x1F96C, 0x1F970), // ; Basic_Emoji ; leafy green # 11.0 [5] (🥬..🥰)
|
|
||||||
(0x1F971, 0x1F971), // ; Basic_Emoji ; yawning face # 12.0 [1] (🥱)
|
|
||||||
(0x1F973, 0x1F976), // ; Basic_Emoji ; partying face # 11.0 [4] (🥳..🥶)
|
|
||||||
(0x1F97A, 0x1F97A), // ; Basic_Emoji ; pleading face # 11.0 [1] (🥺)
|
|
||||||
(0x1F97B, 0x1F97B), // ; Basic_Emoji ; sari # 12.0 [1] (🥻)
|
|
||||||
(0x1F97C, 0x1F97F), // ; Basic_Emoji ; lab coat # 11.0 [4] (🥼..🥿)
|
|
||||||
(0x1F980, 0x1F984), // ; Basic_Emoji ; crab # 8.0 [5] (🦀..🦄)
|
|
||||||
(0x1F985, 0x1F991), // ; Basic_Emoji ; eagle # 9.0 [13] (🦅..🦑)
|
|
||||||
(0x1F992, 0x1F997), // ; Basic_Emoji ; giraffe # 10.0 [6] (🦒..🦗)
|
|
||||||
(0x1F998, 0x1F9A2), // ; Basic_Emoji ; kangaroo # 11.0 [11] (🦘..🦢)
|
|
||||||
(0x1F9A5, 0x1F9AA), // ; Basic_Emoji ; sloth # 12.0 [6] (🦥..🦪)
|
|
||||||
(0x1F9AE, 0x1F9AF), // ; Basic_Emoji ; guide dog # 12.0 [2] (🦮..🦯)
|
|
||||||
(0x1F9B0, 0x1F9B9), // ; Basic_Emoji ; red hair # 11.0 [10] (🦰..🦹)
|
|
||||||
(0x1F9BA, 0x1F9BF), // ; Basic_Emoji ; safety vest # 12.0 [6] (🦺..🦿)
|
|
||||||
(0x1F9C0, 0x1F9C0), // ; Basic_Emoji ; cheese wedge # 8.0 [1] (🧀)
|
|
||||||
(0x1F9C1, 0x1F9C2), // ; Basic_Emoji ; cupcake # 11.0 [2] (🧁..🧂)
|
|
||||||
(0x1F9C3, 0x1F9CA), // ; Basic_Emoji ; beverage box # 12.0 [8] (🧃..🧊)
|
|
||||||
(0x1F9CD, 0x1F9CF), // ; Basic_Emoji ; person standing # 12.0 [3] (🧍..🧏)
|
|
||||||
(0x1F9D0, 0x1F9E6), // ; Basic_Emoji ; face with monocle # 10.0 [23] (🧐..🧦)
|
|
||||||
(0x1F9E7, 0x1F9FF), // ; Basic_Emoji ; red envelope # 11.0 [25] (🧧..🧿)
|
|
||||||
(0x1FA70, 0x1FA73), // ; Basic_Emoji ; ballet shoes # 12.0 [4] (🩰..🩳)
|
|
||||||
(0x1FA78, 0x1FA7A), // ; Basic_Emoji ; drop of blood # 12.0 [3] (🩸..🩺)
|
|
||||||
(0x1FA80, 0x1FA82), // ; Basic_Emoji ; yo-yo # 12.0 [3] (🪀..🪂)
|
|
||||||
(0x1FA90, 0x1FA95), // ; Basic_Emoji ; ringed planet # 12.0 [6] (🪐..🪕)
|
|
||||||
];
|
|
||||||
/*
|
|
||||||
00A9 FE0F ; Basic_Emoji ; copyright # 3.2 [1] (©️)
|
|
||||||
00AE FE0F ; Basic_Emoji ; registered # 3.2 [1] (®️)
|
|
||||||
203C FE0F ; Basic_Emoji ; double exclamation mark # 3.2 [1] (‼️)
|
|
||||||
2049 FE0F ; Basic_Emoji ; exclamation question mark # 3.2 [1] (⁉️)
|
|
||||||
2122 FE0F ; Basic_Emoji ; trade mark # 3.2 [1] (™️)
|
|
||||||
2139 FE0F ; Basic_Emoji ; information # 3.2 [1] (ℹ️)
|
|
||||||
2194 FE0F ; Basic_Emoji ; left-right arrow # 3.2 [1] (↔️)
|
|
||||||
2195 FE0F ; Basic_Emoji ; up-down arrow # 3.2 [1] (↕️)
|
|
||||||
2196 FE0F ; Basic_Emoji ; up-left arrow # 3.2 [1] (↖️)
|
|
||||||
2197 FE0F ; Basic_Emoji ; up-right arrow # 3.2 [1] (↗️)
|
|
||||||
2198 FE0F ; Basic_Emoji ; down-right arrow # 3.2 [1] (↘️)
|
|
||||||
2199 FE0F ; Basic_Emoji ; down-left arrow # 3.2 [1] (↙️)
|
|
||||||
21A9 FE0F ; Basic_Emoji ; right arrow curving left # 3.2 [1] (↩️)
|
|
||||||
21AA FE0F ; Basic_Emoji ; left arrow curving right # 3.2 [1] (↪️)
|
|
||||||
2328 FE0F ; Basic_Emoji ; keyboard # 3.2 [1] (⌨️)
|
|
||||||
23CF FE0F ; Basic_Emoji ; eject button # 4.0 [1] (⏏️)
|
|
||||||
23ED FE0F ; Basic_Emoji ; next track button # 6.0 [1] (⏭️)
|
|
||||||
23EE FE0F ; Basic_Emoji ; last track button # 6.0 [1] (⏮️)
|
|
||||||
23EF FE0F ; Basic_Emoji ; play or pause button # 6.0 [1] (⏯️)
|
|
||||||
23F1 FE0F ; Basic_Emoji ; stopwatch # 6.0 [1] (⏱️)
|
|
||||||
23F2 FE0F ; Basic_Emoji ; timer clock # 6.0 [1] (⏲️)
|
|
||||||
23F8 FE0F ; Basic_Emoji ; pause button # 7.0 [1] (⏸️)
|
|
||||||
23F9 FE0F ; Basic_Emoji ; stop button # 7.0 [1] (⏹️)
|
|
||||||
23FA FE0F ; Basic_Emoji ; record button # 7.0 [1] (⏺️)
|
|
||||||
24C2 FE0F ; Basic_Emoji ; circled M # 3.2 [1] (Ⓜ️)
|
|
||||||
25AA FE0F ; Basic_Emoji ; black small square # 3.2 [1] (▪️)
|
|
||||||
25AB FE0F ; Basic_Emoji ; white small square # 3.2 [1] (▫️)
|
|
||||||
25B6 FE0F ; Basic_Emoji ; play button # 3.2 [1] (▶️)
|
|
||||||
25C0 FE0F ; Basic_Emoji ; reverse button # 3.2 [1] (◀️)
|
|
||||||
25FB FE0F ; Basic_Emoji ; white medium square # 3.2 [1] (◻️)
|
|
||||||
25FC FE0F ; Basic_Emoji ; black medium square # 3.2 [1] (◼️)
|
|
||||||
2600 FE0F ; Basic_Emoji ; sun # 3.2 [1] (☀️)
|
|
||||||
2601 FE0F ; Basic_Emoji ; cloud # 3.2 [1] (☁️)
|
|
||||||
2602 FE0F ; Basic_Emoji ; umbrella # 3.2 [1] (☂️)
|
|
||||||
2603 FE0F ; Basic_Emoji ; snowman # 3.2 [1] (☃️)
|
|
||||||
2604 FE0F ; Basic_Emoji ; comet # 3.2 [1] (☄️)
|
|
||||||
260E FE0F ; Basic_Emoji ; telephone # 3.2 [1] (☎️)
|
|
||||||
2611 FE0F ; Basic_Emoji ; check box with check # 3.2 [1] (☑️)
|
|
||||||
2618 FE0F ; Basic_Emoji ; shamrock # 4.1 [1] (☘️)
|
|
||||||
261D FE0F ; Basic_Emoji ; index pointing up # 3.2 [1] (☝️)
|
|
||||||
2620 FE0F ; Basic_Emoji ; skull and crossbones # 3.2 [1] (☠️)
|
|
||||||
2622 FE0F ; Basic_Emoji ; radioactive # 3.2 [1] (☢️)
|
|
||||||
2623 FE0F ; Basic_Emoji ; biohazard # 3.2 [1] (☣️)
|
|
||||||
2626 FE0F ; Basic_Emoji ; orthodox cross # 3.2 [1] (☦️)
|
|
||||||
262A FE0F ; Basic_Emoji ; star and crescent # 3.2 [1] (☪️)
|
|
||||||
262E FE0F ; Basic_Emoji ; peace symbol # 3.2 [1] (☮️)
|
|
||||||
262F FE0F ; Basic_Emoji ; yin yang # 3.2 [1] (☯️)
|
|
||||||
2638 FE0F ; Basic_Emoji ; wheel of dharma # 3.2 [1] (☸️)
|
|
||||||
2639 FE0F ; Basic_Emoji ; frowning face # 3.2 [1] (☹️)
|
|
||||||
263A FE0F ; Basic_Emoji ; smiling face # 3.2 [1] (☺️)
|
|
||||||
2640 FE0F ; Basic_Emoji ; female sign # 3.2 [1] (♀️)
|
|
||||||
2642 FE0F ; Basic_Emoji ; male sign # 3.2 [1] (♂️)
|
|
||||||
265F FE0F ; Basic_Emoji ; chess pawn # 3.2 [1] (♟️)
|
|
||||||
2660 FE0F ; Basic_Emoji ; spade suit # 3.2 [1] (♠️)
|
|
||||||
2663 FE0F ; Basic_Emoji ; club suit # 3.2 [1] (♣️)
|
|
||||||
2665 FE0F ; Basic_Emoji ; heart suit # 3.2 [1] (♥️)
|
|
||||||
2666 FE0F ; Basic_Emoji ; diamond suit # 3.2 [1] (♦️)
|
|
||||||
2668 FE0F ; Basic_Emoji ; hot springs # 3.2 [1] (♨️)
|
|
||||||
267B FE0F ; Basic_Emoji ; recycling symbol # 3.2 [1] (♻️)
|
|
||||||
267E FE0F ; Basic_Emoji ; infinity # 4.1 [1] (♾️)
|
|
||||||
2692 FE0F ; Basic_Emoji ; hammer and pick # 4.1 [1] (⚒️)
|
|
||||||
2694 FE0F ; Basic_Emoji ; crossed swords # 4.1 [1] (⚔️)
|
|
||||||
2695 FE0F ; Basic_Emoji ; medical symbol # 4.1 [1] (⚕️)
|
|
||||||
2696 FE0F ; Basic_Emoji ; balance scale # 4.1 [1] (⚖️)
|
|
||||||
2697 FE0F ; Basic_Emoji ; alembic # 4.1 [1] (⚗️)
|
|
||||||
2699 FE0F ; Basic_Emoji ; gear # 4.1 [1] (⚙️)
|
|
||||||
269B FE0F ; Basic_Emoji ; atom symbol # 4.1 [1] (⚛️)
|
|
||||||
269C FE0F ; Basic_Emoji ; fleur-de-lis # 4.1 [1] (⚜️)
|
|
||||||
26A0 FE0F ; Basic_Emoji ; warning # 4.0 [1] (⚠️)
|
|
||||||
26B0 FE0F ; Basic_Emoji ; coffin # 4.1 [1] (⚰️)
|
|
||||||
26B1 FE0F ; Basic_Emoji ; funeral urn # 4.1 [1] (⚱️)
|
|
||||||
26C8 FE0F ; Basic_Emoji ; cloud with lightning and rain # 5.2 [1] (⛈️)
|
|
||||||
26CF FE0F ; Basic_Emoji ; pick # 5.2 [1] (⛏️)
|
|
||||||
26D1 FE0F ; Basic_Emoji ; rescue worker’s helmet # 5.2 [1] (⛑️)
|
|
||||||
26D3 FE0F ; Basic_Emoji ; chains # 5.2 [1] (⛓️)
|
|
||||||
26E9 FE0F ; Basic_Emoji ; shinto shrine # 5.2 [1] (⛩️)
|
|
||||||
26F0 FE0F ; Basic_Emoji ; mountain # 5.2 [1] (⛰️)
|
|
||||||
26F1 FE0F ; Basic_Emoji ; umbrella on ground # 5.2 [1] (⛱️)
|
|
||||||
26F4 FE0F ; Basic_Emoji ; ferry # 5.2 [1] (⛴️)
|
|
||||||
26F7 FE0F ; Basic_Emoji ; skier # 5.2 [1] (⛷️)
|
|
||||||
26F8 FE0F ; Basic_Emoji ; ice skate # 5.2 [1] (⛸️)
|
|
||||||
26F9 FE0F ; Basic_Emoji ; person bouncing ball # 5.2 [1] (⛹️)
|
|
||||||
2702 FE0F ; Basic_Emoji ; scissors # 3.2 [1] (✂️)
|
|
||||||
2708 FE0F ; Basic_Emoji ; airplane # 3.2 [1] (✈️)
|
|
||||||
2709 FE0F ; Basic_Emoji ; envelope # 3.2 [1] (✉️)
|
|
||||||
270C FE0F ; Basic_Emoji ; victory hand # 3.2 [1] (✌️)
|
|
||||||
270D FE0F ; Basic_Emoji ; writing hand # 3.2 [1] (✍️)
|
|
||||||
270F FE0F ; Basic_Emoji ; pencil # 3.2 [1] (✏️)
|
|
||||||
2712 FE0F ; Basic_Emoji ; black nib # 3.2 [1] (✒️)
|
|
||||||
2714 FE0F ; Basic_Emoji ; check mark # 3.2 [1] (✔️)
|
|
||||||
2716 FE0F ; Basic_Emoji ; multiplication sign # 3.2 [1] (✖️)
|
|
||||||
271D FE0F ; Basic_Emoji ; latin cross # 3.2 [1] (✝️)
|
|
||||||
2721 FE0F ; Basic_Emoji ; star of David # 3.2 [1] (✡️)
|
|
||||||
2733 FE0F ; Basic_Emoji ; eight-spoked asterisk # 3.2 [1] (✳️)
|
|
||||||
2734 FE0F ; Basic_Emoji ; eight-pointed star # 3.2 [1] (✴️)
|
|
||||||
2744 FE0F ; Basic_Emoji ; snowflake # 3.2 [1] (❄️)
|
|
||||||
2747 FE0F ; Basic_Emoji ; sparkle # 3.2 [1] (❇️)
|
|
||||||
2763 FE0F ; Basic_Emoji ; heart exclamation # 3.2 [1] (❣️)
|
|
||||||
2764 FE0F ; Basic_Emoji ; red heart # 3.2 [1] (❤️)
|
|
||||||
27A1 FE0F ; Basic_Emoji ; right arrow # 3.2 [1] (➡️)
|
|
||||||
2934 FE0F ; Basic_Emoji ; right arrow curving up # 3.2 [1] (⤴️)
|
|
||||||
2935 FE0F ; Basic_Emoji ; right arrow curving down # 3.2 [1] (⤵️)
|
|
||||||
2B05 FE0F ; Basic_Emoji ; left arrow # 4.0 [1] (⬅️)
|
|
||||||
2B06 FE0F ; Basic_Emoji ; up arrow # 4.0 [1] (⬆️)
|
|
||||||
2B07 FE0F ; Basic_Emoji ; down arrow # 4.0 [1] (⬇️)
|
|
||||||
3030 FE0F ; Basic_Emoji ; wavy dash # 3.2 [1] (〰️)
|
|
||||||
303D FE0F ; Basic_Emoji ; part alternation mark # 3.2 [1] (〽️)
|
|
||||||
3297 FE0F ; Basic_Emoji ; Japanese “congratulations” button # 3.2 [1] (㊗️)
|
|
||||||
3299 FE0F ; Basic_Emoji ; Japanese “secret” button # 3.2 [1] (㊙️)
|
|
||||||
1F170 FE0F ; Basic_Emoji ; A button (blood type) # 6.0 [1] (🅰️)
|
|
||||||
1F171 FE0F ; Basic_Emoji ; B button (blood type) # 6.0 [1] (🅱️)
|
|
||||||
1F17E FE0F ; Basic_Emoji ; O button (blood type) # 6.0 [1] (🅾️)
|
|
||||||
1F17F FE0F ; Basic_Emoji ; P button # 5.2 [1] (🅿️)
|
|
||||||
1F202 FE0F ; Basic_Emoji ; Japanese “service charge” button # 6.0 [1] (🈂️)
|
|
||||||
1F237 FE0F ; Basic_Emoji ; Japanese “monthly amount” button # 6.0 [1] (🈷️)
|
|
||||||
1F321 FE0F ; Basic_Emoji ; thermometer # 7.0 [1] (🌡️)
|
|
||||||
1F324 FE0F ; Basic_Emoji ; sun behind small cloud # 7.0 [1] (🌤️)
|
|
||||||
1F325 FE0F ; Basic_Emoji ; sun behind large cloud # 7.0 [1] (🌥️)
|
|
||||||
1F326 FE0F ; Basic_Emoji ; sun behind rain cloud # 7.0 [1] (🌦️)
|
|
||||||
1F327 FE0F ; Basic_Emoji ; cloud with rain # 7.0 [1] (🌧️)
|
|
||||||
1F328 FE0F ; Basic_Emoji ; cloud with snow # 7.0 [1] (🌨️)
|
|
||||||
1F329 FE0F ; Basic_Emoji ; cloud with lightning # 7.0 [1] (🌩️)
|
|
||||||
1F32A FE0F ; Basic_Emoji ; tornado # 7.0 [1] (🌪️)
|
|
||||||
1F32B FE0F ; Basic_Emoji ; fog # 7.0 [1] (🌫️)
|
|
||||||
1F32C FE0F ; Basic_Emoji ; wind face # 7.0 [1] (🌬️)
|
|
||||||
1F336 FE0F ; Basic_Emoji ; hot pepper # 7.0 [1] (🌶️)
|
|
||||||
1F37D FE0F ; Basic_Emoji ; fork and knife with plate # 7.0 [1] (🍽️)
|
|
||||||
1F396 FE0F ; Basic_Emoji ; military medal # 7.0 [1] (🎖️)
|
|
||||||
1F397 FE0F ; Basic_Emoji ; reminder ribbon # 7.0 [1] (🎗️)
|
|
||||||
1F399 FE0F ; Basic_Emoji ; studio microphone # 7.0 [1] (🎙️)
|
|
||||||
1F39A FE0F ; Basic_Emoji ; level slider # 7.0 [1] (🎚️)
|
|
||||||
1F39B FE0F ; Basic_Emoji ; control knobs # 7.0 [1] (🎛️)
|
|
||||||
1F39E FE0F ; Basic_Emoji ; film frames # 7.0 [1] (🎞️)
|
|
||||||
1F39F FE0F ; Basic_Emoji ; admission tickets # 7.0 [1] (🎟️)
|
|
||||||
1F3CB FE0F ; Basic_Emoji ; person lifting weights # 7.0 [1] (🏋️)
|
|
||||||
1F3CC FE0F ; Basic_Emoji ; person golfing # 7.0 [1] (🏌️)
|
|
||||||
1F3CD FE0F ; Basic_Emoji ; motorcycle # 7.0 [1] (🏍️)
|
|
||||||
1F3CE FE0F ; Basic_Emoji ; racing car # 7.0 [1] (🏎️)
|
|
||||||
1F3D4 FE0F ; Basic_Emoji ; snow-capped mountain # 7.0 [1] (🏔️)
|
|
||||||
1F3D5 FE0F ; Basic_Emoji ; camping # 7.0 [1] (🏕️)
|
|
||||||
1F3D6 FE0F ; Basic_Emoji ; beach with umbrella # 7.0 [1] (🏖️)
|
|
||||||
1F3D7 FE0F ; Basic_Emoji ; building construction # 7.0 [1] (🏗️)
|
|
||||||
1F3D8 FE0F ; Basic_Emoji ; houses # 7.0 [1] (🏘️)
|
|
||||||
1F3D9 FE0F ; Basic_Emoji ; cityscape # 7.0 [1] (🏙️)
|
|
||||||
1F3DA FE0F ; Basic_Emoji ; derelict house # 7.0 [1] (🏚️)
|
|
||||||
1F3DB FE0F ; Basic_Emoji ; classical building # 7.0 [1] (🏛️)
|
|
||||||
1F3DC FE0F ; Basic_Emoji ; desert # 7.0 [1] (🏜️)
|
|
||||||
1F3DD FE0F ; Basic_Emoji ; desert island # 7.0 [1] (🏝️)
|
|
||||||
1F3DE FE0F ; Basic_Emoji ; national park # 7.0 [1] (🏞️)
|
|
||||||
1F3DF FE0F ; Basic_Emoji ; stadium # 7.0 [1] (🏟️)
|
|
||||||
1F3F3 FE0F ; Basic_Emoji ; white flag # 7.0 [1] (🏳️)
|
|
||||||
1F3F5 FE0F ; Basic_Emoji ; rosette # 7.0 [1] (🏵️)
|
|
||||||
1F3F7 FE0F ; Basic_Emoji ; label # 7.0 [1] (🏷️)
|
|
||||||
1F43F FE0F ; Basic_Emoji ; chipmunk # 7.0 [1] (🐿️)
|
|
||||||
1F441 FE0F ; Basic_Emoji ; eye # 7.0 [1] (👁️)
|
|
||||||
1F4FD FE0F ; Basic_Emoji ; film projector # 7.0 [1] (📽️)
|
|
||||||
1F549 FE0F ; Basic_Emoji ; om # 7.0 [1] (🕉️)
|
|
||||||
1F54A FE0F ; Basic_Emoji ; dove # 7.0 [1] (🕊️)
|
|
||||||
1F56F FE0F ; Basic_Emoji ; candle # 7.0 [1] (🕯️)
|
|
||||||
1F570 FE0F ; Basic_Emoji ; mantelpiece clock # 7.0 [1] (🕰️)
|
|
||||||
1F573 FE0F ; Basic_Emoji ; hole # 7.0 [1] (🕳️)
|
|
||||||
1F574 FE0F ; Basic_Emoji ; man in suit levitating # 7.0 [1] (🕴️)
|
|
||||||
1F575 FE0F ; Basic_Emoji ; detective # 7.0 [1] (🕵️)
|
|
||||||
1F576 FE0F ; Basic_Emoji ; sunglasses # 7.0 [1] (🕶️)
|
|
||||||
1F577 FE0F ; Basic_Emoji ; spider # 7.0 [1] (🕷️)
|
|
||||||
1F578 FE0F ; Basic_Emoji ; spider web # 7.0 [1] (🕸️)
|
|
||||||
1F579 FE0F ; Basic_Emoji ; joystick # 7.0 [1] (🕹️)
|
|
||||||
1F587 FE0F ; Basic_Emoji ; linked paperclips # 7.0 [1] (🖇️)
|
|
||||||
1F58A FE0F ; Basic_Emoji ; pen # 7.0 [1] (🖊️)
|
|
||||||
1F58B FE0F ; Basic_Emoji ; fountain pen # 7.0 [1] (🖋️)
|
|
||||||
1F58C FE0F ; Basic_Emoji ; paintbrush # 7.0 [1] (🖌️)
|
|
||||||
1F58D FE0F ; Basic_Emoji ; crayon # 7.0 [1] (🖍️)
|
|
||||||
1F590 FE0F ; Basic_Emoji ; hand with fingers splayed # 7.0 [1] (🖐️)
|
|
||||||
1F5A5 FE0F ; Basic_Emoji ; desktop computer # 7.0 [1] (🖥️)
|
|
||||||
1F5A8 FE0F ; Basic_Emoji ; printer # 7.0 [1] (🖨️)
|
|
||||||
1F5B1 FE0F ; Basic_Emoji ; computer mouse # 7.0 [1] (🖱️)
|
|
||||||
1F5B2 FE0F ; Basic_Emoji ; trackball # 7.0 [1] (🖲️)
|
|
||||||
1F5BC FE0F ; Basic_Emoji ; framed picture # 7.0 [1] (🖼️)
|
|
||||||
1F5C2 FE0F ; Basic_Emoji ; card index dividers # 7.0 [1] (🗂️)
|
|
||||||
1F5C3 FE0F ; Basic_Emoji ; card file box # 7.0 [1] (🗃️)
|
|
||||||
1F5C4 FE0F ; Basic_Emoji ; file cabinet # 7.0 [1] (🗄️)
|
|
||||||
1F5D1 FE0F ; Basic_Emoji ; wastebasket # 7.0 [1] (🗑️)
|
|
||||||
1F5D2 FE0F ; Basic_Emoji ; spiral notepad # 7.0 [1] (🗒️)
|
|
||||||
1F5D3 FE0F ; Basic_Emoji ; spiral calendar # 7.0 [1] (🗓️)
|
|
||||||
1F5DC FE0F ; Basic_Emoji ; clamp # 7.0 [1] (🗜️)
|
|
||||||
1F5DD FE0F ; Basic_Emoji ; old key # 7.0 [1] (🗝️)
|
|
||||||
1F5DE FE0F ; Basic_Emoji ; rolled-up newspaper # 7.0 [1] (🗞️)
|
|
||||||
1F5E1 FE0F ; Basic_Emoji ; dagger # 7.0 [1] (🗡️)
|
|
||||||
1F5E3 FE0F ; Basic_Emoji ; speaking head # 7.0 [1] (🗣️)
|
|
||||||
1F5E8 FE0F ; Basic_Emoji ; left speech bubble # 7.0 [1] (🗨️)
|
|
||||||
1F5EF FE0F ; Basic_Emoji ; right anger bubble # 7.0 [1] (🗯️)
|
|
||||||
1F5F3 FE0F ; Basic_Emoji ; ballot box with ballot # 7.0 [1] (🗳️)
|
|
||||||
1F5FA FE0F ; Basic_Emoji ; world map # 7.0 [1] (🗺️)
|
|
||||||
1F6CB FE0F ; Basic_Emoji ; couch and lamp # 7.0 [1] (🛋️)
|
|
||||||
1F6CD FE0F ; Basic_Emoji ; shopping bags # 7.0 [1] (🛍️)
|
|
||||||
1F6CE FE0F ; Basic_Emoji ; bellhop bell # 7.0 [1] (🛎️)
|
|
||||||
1F6CF FE0F ; Basic_Emoji ; bed # 7.0 [1] (🛏️)
|
|
||||||
1F6E0 FE0F ; Basic_Emoji ; hammer and wrench # 7.0 [1] (🛠️)
|
|
||||||
1F6E1 FE0F ; Basic_Emoji ; shield # 7.0 [1] (🛡️)
|
|
||||||
1F6E2 FE0F ; Basic_Emoji ; oil drum # 7.0 [1] (🛢️)
|
|
||||||
1F6E3 FE0F ; Basic_Emoji ; motorway # 7.0 [1] (🛣️)
|
|
||||||
1F6E4 FE0F ; Basic_Emoji ; railway track # 7.0 [1] (🛤️)
|
|
||||||
1F6E5 FE0F ; Basic_Emoji ; motor boat # 7.0 [1] (🛥️)
|
|
||||||
1F6E9 FE0F ; Basic_Emoji ; small airplane # 7.0 [1] (🛩️)
|
|
||||||
1F6F0 FE0F ; Basic_Emoji ; satellite # 7.0 [1] (🛰️)
|
|
||||||
1F6F3 FE0F ; Basic_Emoji ; passenger ship # 7.0 [1] (🛳️)
|
|
||||||
*/
|
|
||||||
|
|
Loading…
Reference in New Issue