feat: implement #1036 join prefix to word (#2299)

* feat: implement #1036 join prefix to word

* fix: appease clippy

* fix: act on advice in review
This commit is contained in:
Andrew Dunbar
2025-12-05 18:36:15 +00:00
committed by GitHub
parent d0d0ac72df
commit cc15110b69
25 changed files with 423 additions and 60 deletions

View File

@@ -9,7 +9,7 @@ object hello extends ScalaModule {
ivy"com.lihaoyi::mainargs:0.6.2" // for CLI argument parsing
)
// Define an test sub-module using a test framework.
// Define an test submodule using a test framework.
object test extends ScalaTests {
def testFramework = "utest.runner.Framework"
def ivyDeps = Agg(

View File

@@ -53949,6 +53949,7 @@ U-turn/NgSVdG
uh-huh
uh-oh
un-American/J
up front/JR
use case/NgS
user-friendly/J
UTF-16/Ng

View File

@@ -80,6 +80,13 @@ impl Expr for SequenceExpr {
impl SequenceExpr {
// Constructor methods
// Single token methods
/// Construct a new sequence with an [`AnyPattern`] at the beginning of the operation list.
pub fn anything() -> Self {
Self::default().then_anything()
}
// Single word token methods
/// Construct a new sequence with a [`Word`] at the beginning of the operation list.
@@ -166,11 +173,21 @@ impl SequenceExpr {
self.then(WordSet::new(words))
}
/// Shorthand for [`Self::then_word_set`].
pub fn t_set(self, words: &'static [&'static str]) -> Self {
self.then_word_set(words)
}
/// Match against one or more whitespace tokens.
pub fn then_whitespace(self) -> Self {
self.then(WhitespacePattern)
}
/// Shorthand for [`Self::then_whitespace`].
pub fn t_ws(self) -> Self {
self.then_whitespace()
}
/// Match against one or more whitespace tokens.
pub fn then_whitespace_or_hyphen(self) -> Self {
self.then(WhitespacePattern.or(|tok: &Token, _: &[char]| tok.kind.is_hyphen()))
@@ -181,11 +198,6 @@ impl SequenceExpr {
self.then_whitespace_or_hyphen()
}
/// Shorthand for [`Self::then_whitespace`].
pub fn t_ws(self) -> Self {
self.then_whitespace()
}
pub fn then_one_or_more(self, expr: impl Expr + 'static) -> Self {
self.then(Repeating::new(Box::new(expr), 1))
}

View File

@@ -41,12 +41,7 @@ impl Default for CompoundNounAfterDetAdj {
let mut expr = All::default();
expr.add(context_expr);
expr.add(
SequenceExpr::default()
.t_any()
.t_any()
.then(split_expr.clone()),
);
expr.add(SequenceExpr::anything().t_any().then(split_expr.clone()));
Self {
expr: Box::new(expr),

View File

@@ -0,0 +1,206 @@
use crate::{
Lint, Token, TokenKind, TokenStringExt,
expr::{Expr, OwnedExprExt, SequenceExpr},
linting::{ExprLinter, LintKind, Suggestion, expr_linter::Chunk},
spell::Dictionary,
};
pub struct DisjointPrefixes<D> {
expr: Box<dyn Expr>,
dict: D,
}
// Known false positives not to join to these prefixes:
const OUT_EXCEPTIONS: &[&str] = &["boxes", "facing", "live", "numbers", "playing"];
const OVER_EXCEPTIONS: &[&str] = &["all", "joy", "long", "night", "reading", "steps", "time"];
const UNDER_EXCEPTIONS: &[&str] = &["development", "mine"];
const UP_EXCEPTIONS: &[&str] = &["loading", "right", "state", "time", "trend"];
impl<D> DisjointPrefixes<D>
where
D: Dictionary,
{
pub fn new(dict: D) -> Self {
Self {
expr: Box::new(
SequenceExpr::word_set(&[
// These prefixes rarely cause false positives
"anti", "auto", "bi", "counter", "de", "dis", "extra", "fore", "hyper", "il",
"im", "inter", "ir", "macro", "mal", "micro", "mid", "mini", "mis", "mono",
"multi", "non", "omni", "post", "pre", "pro", "re", "semi", "sub", "super",
"trans", "tri", "ultra", "un", "uni",
// "co" has one very common false positive: co-op != coop
"co",
// These prefixes are all also words in their own right, which leads to more false positives.
"out", "over", "under",
"up",
// These prefixes are commented out due to too many false positives
// or incorrect transformations:
// "a": a live -> alive
// "in": in C -> inc; in action -> inaction
])
.t_ws_h()
.then_kind_either(TokenKind::is_verb, TokenKind::is_noun)
.then_optional_hyphen()
.and_not(SequenceExpr::any_of(vec![
// No trailing hyphen. Ex: Custom patterns take precedence over built-in patterns -> overbuilt
Box::new(SequenceExpr::anything().t_any().t_any().then_hyphen()),
// Don't merge "co op" whether separated by space or hyphen.
Box::new(SequenceExpr::aco("co").t_any().t_set(&["op", "ops"])),
// Merge these if they're separated by hyphen, but not space.
Box::new(SequenceExpr::aco("out").t_ws().t_set(OUT_EXCEPTIONS)),
Box::new(SequenceExpr::aco("over").t_ws().t_set(OVER_EXCEPTIONS)),
Box::new(SequenceExpr::aco("under").t_ws().t_set(UNDER_EXCEPTIONS)),
Box::new(SequenceExpr::aco("up").t_ws().t_set(UP_EXCEPTIONS)),
])),
),
dict,
}
}
}
impl<D> ExprLinter for DisjointPrefixes<D>
where
D: Dictionary,
{
type Unit = Chunk;
fn expr(&self) -> &dyn Expr {
self.expr.as_ref()
}
fn match_to_lint_with_context(
&self,
toks: &[Token],
src: &[char],
ctx: Option<(&[Token], &[Token])>,
) -> Option<Lint> {
let toks_span = toks.span()?;
let (pre, _) = ctx?;
// Cloud Native Pub-Sub System at Pinterest -> subsystem
if pre.last().is_some_and(|p| p.kind.is_hyphen()) {
return None;
}
// Avoid including text from unlintable sections between tokens
// that could result from naively using toks.span()?.get_content_string(src)
let original = format!(
"{}{}{}",
toks[0].span.get_content_string(src),
if toks[1].kind.is_hyphen() { '-' } else { ' ' },
toks[2].span.get_content_string(src)
);
// If the original form is in the dictionary, return None
if self.dict.contains_word_str(&original) {
return None;
}
let mut hyphenated = None;
if !toks[1].kind.is_hyphen() {
hyphenated = Some(format!(
"{}-{}",
toks[0].span.get_content_string(src),
toks[2].span.get_content_string(src)
));
}
let joined = Some(format!(
"{}{}",
toks[0].span.get_content_string(src),
toks[2].span.get_content_string(src)
));
// Check if either joined or hyphenated form is in the dictionary
let joined_valid = joined
.as_ref()
.is_some_and(|j| self.dict.contains_word_str(j));
let hyphenated_valid = hyphenated
.as_ref()
.is_some_and(|h| self.dict.contains_word_str(h));
if !joined_valid && !hyphenated_valid {
return None;
}
// Joining with a hyphen when original is separated by space is more likely correct
// if hyphenated form is in the dictionary. So add first if verified.
// Joining when separated by a space is more common but also has more false positives, so add them second.
let suggestions = [(&hyphenated, hyphenated_valid), (&joined, joined_valid)]
.into_iter()
.filter_map(|(word, is_valid)| word.as_ref().filter(|_| is_valid))
.collect::<Vec<_>>();
let suggestions = suggestions
.iter()
.map(|s| {
Suggestion::replace_with_match_case(s.chars().collect(), toks_span.get_content(src))
})
.collect();
Some(Lint {
span: toks_span,
lint_kind: LintKind::Spelling,
suggestions,
message: "This looks like a prefix that can be joined with the rest of the word."
.to_string(),
..Default::default()
})
}
fn description(&self) -> &str {
"Looks for words with their prefixes written with a space or hyphen between instead of joined."
}
}
#[cfg(test)]
mod tests {
use super::DisjointPrefixes;
use crate::{
linting::tests::{assert_no_lints, assert_suggestion_result},
spell::FstDictionary,
};
#[test]
fn fix_hyphenated_to_joined() {
assert_suggestion_result(
"Download pre-built binaries or build from source.",
DisjointPrefixes::new(FstDictionary::curated()),
"Download prebuilt binaries or build from source.",
);
}
#[test]
fn fix_open_to_joined() {
assert_suggestion_result(
"Advanced Nginx configuration available for super users",
DisjointPrefixes::new(FstDictionary::curated()),
"Advanced Nginx configuration available for superusers",
);
}
#[test]
fn dont_join_open_co_op() {
assert_no_lints(
"They are cheaper at the co op.",
DisjointPrefixes::new(FstDictionary::curated()),
);
}
#[test]
fn dont_join_hyphenated_co_op() {
assert_no_lints(
"Almost everything is cheaper at the co-op.",
DisjointPrefixes::new(FstDictionary::curated()),
);
}
#[test]
fn fix_open_to_hyphenated() {
assert_suggestion_result(
"My hobby is de extinction of the dinosaurs.",
DisjointPrefixes::new(FstDictionary::curated()),
"My hobby is de-extinction of the dinosaurs.",
);
}
}

View File

@@ -22,14 +22,9 @@ impl Default for Everyday {
.t_ws()
.then_any_word(),
),
Box::new(
SequenceExpr::default()
.t_any()
.t_any()
.then_kind_where(|kind| {
!kind.is_noun() && !kind.is_oov() && !kind.is_verb_progressive_form()
}),
),
Box::new(SequenceExpr::anything().t_any().then_kind_where(|kind| {
!kind.is_noun() && !kind.is_oov() && !kind.is_verb_progressive_form()
})),
]);
let bad_before_every_day = All::new(vec![
@@ -56,8 +51,7 @@ impl Default for Everyday {
.then_any_word(),
),
Box::new(
SequenceExpr::default()
.t_any()
SequenceExpr::anything()
.t_any()
.then_kind_both(TokenKind::is_noun, TokenKind::is_verb)
.t_any()
@@ -72,7 +66,7 @@ impl Default for Everyday {
.then(everyday.clone())
.then_punctuation(),
),
Box::new(SequenceExpr::default().t_any().then_kind_where(|kind| {
Box::new(SequenceExpr::anything().then_kind_where(|kind| {
matches!(
kind,
TokenKind::Punctuation(
@@ -92,8 +86,7 @@ impl Default for Everyday {
.then_punctuation(),
),
Box::new(
SequenceExpr::default()
.t_any()
SequenceExpr::anything()
.t_any()
.t_any()
.t_any()

View File

@@ -16,8 +16,7 @@ impl Default for HowTo {
fn default() -> Self {
let mut pattern = All::default();
let pos_pattern = SequenceExpr::default()
.then_anything()
let pos_pattern = SequenceExpr::anything()
.then_anything()
.t_aco("how")
.then_whitespace()

View File

@@ -18,8 +18,7 @@ impl Default for General {
.or(WordSet::new(&["because"])),
);
let exceptions = SequenceExpr::default()
.then_anything()
let exceptions = SequenceExpr::anything()
.then_anything()
.then(WordSet::new(&["own", "intended"]));

View File

@@ -16,8 +16,7 @@ impl Default for Likewise {
expr.add(SequenceExpr::aco("like").then_whitespace().t_aco("wise"));
expr.add(
SequenceExpr::default().then_unless(
SequenceExpr::default()
.then_anything()
SequenceExpr::anything()
.then_whitespace()
.then_anything()
.then_whitespace()

View File

@@ -50,6 +50,7 @@ use super::currency_placement::CurrencyPlacement;
use super::despite_of::DespiteOf;
use super::didnt::Didnt;
use super::discourse_markers::DiscourseMarkers;
use super::disjoint_prefixes::DisjointPrefixes;
use super::dot_initialisms::DotInitialisms;
use super::double_click::DoubleClick;
use super::double_modal::DoubleModal;
@@ -690,6 +691,12 @@ impl LintGroup {
out.add("MassPlurals", MassPlurals::new(dictionary.clone()));
out.config.set_rule_enabled("MassPlurals", true);
out.add_chunk_expr_linter(
"DisjointPrefixes",
DisjointPrefixes::new(dictionary.clone()),
);
out.config.set_rule_enabled("DisjointPrefixes", true);
out
}
@@ -830,7 +837,7 @@ mod tests {
#[test]
fn dont_flag_low_hanging_fruit_desc() {
assert_no_lints(
"Corrects non-standard variants of low-hanging fruit.",
"Corrects nonstandard variants of low-hanging fruit.",
test_group(),
);
}

View File

@@ -45,6 +45,7 @@ mod despite_of;
mod determiner_without_noun;
mod didnt;
mod discourse_markers;
mod disjoint_prefixes;
mod dot_initialisms;
mod double_click;
mod double_modal;

View File

@@ -23,8 +23,7 @@ impl Default for MostNumber {
),
// Context pattern
Box::new(
SequenceExpr::default()
.then_anything()
SequenceExpr::anything()
.then_anything()
.then_anything()
.then_anything()

View File

@@ -27,8 +27,7 @@ impl Default for NeedToNoun {
Box::new(WordSet::new(&["about", "it"])),
]);
let exceptions = SequenceExpr::default()
.t_any()
let exceptions = SequenceExpr::anything()
.t_any()
.t_any()
.t_any()

View File

@@ -40,16 +40,13 @@ impl Default for OpenCompounds {
}
let compound = Lrc::new(SequenceExpr::default().then(compound_wordset));
let with_prev = SequenceExpr::default()
.then_anything()
.then(compound.clone());
let with_prev = SequenceExpr::anything().then(compound.clone());
let with_next = SequenceExpr::default()
.then(compound.clone())
.then_anything();
let with_prev_and_next = SequenceExpr::default()
.then_anything()
let with_prev_and_next = SequenceExpr::anything()
.then(compound.clone())
.then_anything();

View File

@@ -249,7 +249,7 @@ pub fn lint_group() -> LintGroup {
["in built", "in-built", "built in"],
["built-in"],
"Prefer the hyphenated compound `built-in`.",
"English convention treats `built-in` as a single, attributive adjective—meaning something integrated from the outset—whereas other forms like `in built` are non-standard and can feel awkward to readers."
"English convention treats `built-in` as a single, attributive adjective—meaning something integrated from the outset—whereas other forms like `in built` are nonstandard and can feel awkward to readers."
),
"ByAccident" => (
["on accident"],
@@ -756,7 +756,7 @@ pub fn lint_group() -> LintGroup {
["low hanging fruit", "low hanging fruits", "low-hanging fruits"],
["low-hanging fruit"],
"The standard form is `low-hanging fruit` with a hyphen and singular form.",
"Corrects non-standard variants of `low-hanging fruit`.",
"Corrects nonstandard variants of `low-hanging fruit`.",
LintKind::Usage
),
"ManagerialReins" => (
@@ -915,7 +915,7 @@ pub fn lint_group() -> LintGroup {
["quite many"],
["quite a few"],
"Use `quite a few` instead of `quite many`.",
"Corrects `quite many` to `quite a few`, which is the more natural and idiomatic phrase in standard English. `Quite many` is considered non-standard usage.",
"Corrects `quite many` to `quite a few`, which is the more natural and idiomatic phrase in standard English. `Quite many` is considered nonstandard usage.",
LintKind::Nonstandard
),
"RapidFire" => (

View File

@@ -23,14 +23,9 @@ where
.then_kind_is_but_is_not(TokenKind::is_plural_nominal, TokenKind::is_singular_nominal)
.t_ws()
.then(UPOSSet::new(&[UPOS::NOUN, UPOS::PROPN]))
.then_optional(SequenceExpr::default().t_any().t_any());
.then_optional(SequenceExpr::anything().t_any());
let additional_req = SequenceExpr::default()
.t_any()
.t_any()
.t_any()
.t_any()
.then_noun();
let additional_req = SequenceExpr::anything().t_any().t_any().t_any().then_noun();
let exceptions = SequenceExpr::default()
.then_unless(|tok: &Token, _: &[char]| tok.kind.is_demonstrative_determiner())

View File

@@ -84,7 +84,7 @@ impl ExprLinter for ShootOneselfInTheFoot {
}
fn description(&self) -> &str {
"Corrects non-standard variants of 'shoot oneself in the foot'."
"Corrects nonstandard variants of 'shoot oneself in the foot'."
}
}

View File

@@ -29,8 +29,7 @@ impl Default for VerbToAdjective {
.t_ws()
.then(UPOSSet::new(&[UPOS::NOUN, UPOS::PROPN]));
let exceptions = SequenceExpr::default()
.t_any()
let exceptions = SequenceExpr::anything()
.t_any()
.then_unless(WordSet::new(&["very"]));

View File

@@ -20,8 +20,7 @@ impl Default for WayTooAdjective {
.t_ws()
.then(UPOSSet::new(&[UPOS::ADJ]).or(WordSet::new(&["much"])));
let exceptions = SequenceExpr::default()
.t_any()
let exceptions = SequenceExpr::anything()
.t_any()
.t_any()
.t_any()

View File

@@ -68,7 +68,6 @@ macro_rules! create_org_test {
}
create_test!(whack_bullets.md, 1, Dialect::American);
create_test!(preexisting.md, 0, Dialect::American);
create_test!(issue_109.md, 0, Dialect::American);
create_test!(issue_109_ext.md, 0, Dialect::American);
create_test!(chinese_lorem_ipsum.md, 2, Dialect::American);
@@ -99,7 +98,7 @@ create_test!(issue_2240.md, 0, Dialect::American);
create_test!(issue_2151.md, 4, Dialect::British);
// Make sure it doesn't panic
create_test!(lukas_homework.md, 3, Dialect::American);
create_test!(lukas_homework.md, 4, Dialect::American);
// Org mode tests
create_org_test!(index.org, 49, Dialect::American);

View File

@@ -1 +0,0 @@
Usage of pre-existing should be allowed.

View File

@@ -12,7 +12,7 @@ Nutritionally, yoghurt is celebrated for its health benefits. It is rich in prot
The production methods of yoghurt have evolved significantly over time, from traditional artisanal practices to advanced industrial techniques. Modern yoghurt manufacturing employs precise control of temperature, bacterial cultures, and incubation processes to ensure consistent quality, taste, and nutritional content. Additionally, innovations in packaging and preservation have expanded yoghurt's accessibility and convenience, making it an ubiquitous presence in supermarkets worldwide.
However, yoghurt production and consumption also present certain challenges. Concerns around sustainability, environmental impact, and ethical dairy farming practices have encouraged a shift toward organic and plant-based alternatives. This has spurred market growth for non-dairy yoghurts made from ingredients such as coconut, almond, oat, and soy, reflecting evolving consumer preferences and dietary needs.
However, yoghurt production and consumption also present certain challenges. Concerns around sustainability, environmental impact, and ethical dairy farming practices have encouraged a shift toward organic and plant-based alternatives. This has spurred market growth for nondairy yoghurts made from ingredients such as coconut, almond, oat, and soy, reflecting evolving consumer preferences and dietary needs.
In conclusion, yoghurt is much more than a simple dairy product—it is a cultural and nutritional cornerstone that continues to adapt and thrive across global culinary traditions. Its enduring popularity is a testament to its delicious versatility, health benefits, and adaptability to changing dietary trends, ensuring yoghurt's continued prominence in diets around the world.

View File

@@ -303,6 +303,16 @@ Suggest:
Lint: Spelling (127 priority)
Message: |
122 | science; this is now used for a multi-disciplinary field of data analysis,
| ^~~~~~~~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
123 | including statistics and databases.
Suggest:
- Replace with: “multidisciplinary”
Lint: Spelling (63 priority)
Message: |
126 | field of computing were suggested (albeit facetiously) in the Communications of
@@ -1027,6 +1037,16 @@ Suggest:
Lint: Spelling (127 priority)
Message: |
444 | > easily distinguishable states, such as "on/off", "magnetized/de-magnetized",
| ^~~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
445 | > "high-voltage/low-voltage", etc.).
Suggest:
- Replace with: “demagnetized”
Lint: Capitalization (31 priority)
Message: |
456 | - print 1 at current location.

View File

@@ -71,6 +71,15 @@ Message: |
Lint: Spelling (127 priority)
Message: |
43 | However, there are clearly many more categories and sub-categories. For nouns,
| ^~~~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “subcategories”
Lint: Spelling (63 priority)
Message: |
49 | tags. For example, NN for singular common nouns, NNS for plural common nouns, NP
@@ -371,6 +380,16 @@ Suggest:
Lint: Spelling (127 priority)
Message: |
154 | algorithms one of the most widely used being the bi-directional inference
| ^~~~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
155 | algorithm.
Suggest:
- Replace with: “bidirectional”
Lint: Spelling (63 priority)
Message: |
159 | In 1987, Steven DeRose and Kenneth W. Church independently developed dynamic
@@ -480,6 +499,16 @@ Message: |
Lint: Spelling (127 priority)
Message: |
184 | The methods already discussed involve working from a pre-existing corpus to
| ^~~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
185 | learn tag probabilities. It is, however, also possible to bootstrap using
Suggest:
- Replace with: “preexisting”
Lint: Spelling (63 priority)
Message: |
200 | Some current major algorithms for part-of-speech tagging include the Viterbi

View File

@@ -377,6 +377,16 @@ Message: |
Lint: Spelling (127 priority)
Message: |
137 | one of those men who reach such an acute limited excellence at twenty-one that
138 | everything afterward savors of anti-climax. His family were enormously
| ^~~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “anticlimax”
Lint: Readability (127 priority)
Message: |
138 | everything afterward savors of anti-climax. His family were enormously
@@ -979,6 +989,15 @@ Suggest:
Lint: Spelling (127 priority)
Message: |
775 | Up-stairs, in the solemn echoing drive she let four taxicabs drive away before
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “Upstairs”
Lint: Spelling (63 priority)
Message: |
784 | We backed up to a gray old man who bore an absurd resemblance to John D.
@@ -1453,6 +1472,16 @@ Message: |
Lint: Spelling (127 priority)
Message: |
1188 | piccolos, and low and high drums. The last swimmers have come in from the beach
1189 | now and are dressing up-stairs; the cars from New York are parked five deep in
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “upstairs”
Lint: Spelling (63 priority)
Message: |
1191 | colors, and hair bobbed in strange new ways, and shawls beyond the dreams of
@@ -2059,6 +2088,17 @@ Message: |
Lint: Spelling (127 priority)
Message: |
1745 | I took dinner usually at the Yale Club—for some reason it was the gloomiest
1746 | event of my day—and then I went up-stairs to the library and studied investments
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
1747 | and securities for a conscientious hour. There were generally a few rioters
Suggest:
- Replace with: “upstairs”
Lint: Readability (127 priority)
Message: |
1759 | darkness. At the enchanted metropolitan twilight I felt a haunting loneliness
@@ -2120,6 +2160,16 @@ Message: |
Lint: Spelling (127 priority)
Message: |
1781 | the newspapers—a suggestion that she had moved her ball from a bad lie in the
1782 | semi-final round. The thing approached the proportions of a scandal—then died
| ^~~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “semifinal”
Lint: Readability (127 priority)
Message: |
1789 | thought impossible. She was incurably dishonest. She wasnt able to endure being
@@ -4087,6 +4137,15 @@ Suggest:
Lint: Spelling (127 priority)
Message: |
2789 | Daisy went up-stairs to wash her face—too late I thought with humiliation of my
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “upstairs”
Lint: Formatting (255 priority)
Message: |
2806 | was in he answered: Thats my affair,” before he realized that it wasnt an
@@ -4149,6 +4208,15 @@ Message: |
Lint: Spelling (127 priority)
Message: |
2840 | We went up-stairs, through period bedrooms swathed in rose and lavender silk and
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “upstairs”
Lint: Spelling (63 priority)
Message: |
2842 | sunken baths—intruding into one chamber where a dishevelled man in pajamas was
@@ -5259,6 +5327,15 @@ Message: |
Lint: Spelling (127 priority)
Message: |
3765 | They went up-stairs to get ready while we three men stood there shuffling the
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “upstairs”
Lint: Capitalization (127 priority)
Message: |
3795 | song of it. . . . High in a white palace the kings daughter, the golden girl. .
@@ -6483,6 +6560,16 @@ Message: |
Lint: Spelling (127 priority)
Message: |
4780 | her as his tent out at camp was to him. There was a ripe mystery about it, a
4781 | hint of bedrooms up-stairs more beautiful and cool than other bedrooms, of gay
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “upstairs”
Lint: Readability (127 priority)
Message: |
4797 | pretenses. I dont mean that he had traded on his phantom millions, but he had
@@ -7136,6 +7223,16 @@ Suggest:
Lint: Spelling (127 priority)
Message: |
5299 | Some one started to ask me questions, but I broke away and going up-stairs
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
5300 | looked hastily through the unlocked parts of his desk—hed never told me
Suggest:
- Replace with: “upstairs”
Lint: Spelling (63 priority)
Message: |
5304 | Next morning I sent the butler to New York with a letter to Wolfshiem, which
@@ -7359,6 +7456,15 @@ Message: |
Lint: Spelling (127 priority)
Message: |
5390 | began to be mixed with an awed pride. I helped him to a bedroom up-stairs; while
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “upstairs”
Lint: Spelling (63 priority)
Message: |
5396 | “Gatz is my name.”
@@ -8083,6 +8189,16 @@ Message: |
Lint: Spelling (127 priority)
Message: |
5764 | ready to leave, and when I sent down word that we werent in he tried to force
5765 | his way up-stairs. He was crazy enough to kill me if I hadnt told him who owned
| ^~~~~~~~~ This looks like a prefix that can be joined with the rest of the word.
Suggest:
- Replace with: “upstairs”
Lint: Readability (127 priority)
Message: |
5775 | “And if you think I didnt have my share of suffering—look here, when I went to