diff --git a/src/main.rs b/src/main.rs
index f754e59..95841c4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -115,75 +115,72 @@ fn parse_file(file: impl io::Read) -> Result<json::JsonValue, Box<std::error::Er
 	};
 	let mut ctx = &mut context;
 
-	for line in reader.lines() {
-		// ignore empty lines
-		let line_str = String::from(line.unwrap().trim());
-		let line_s = &line_str;
-		if line_s.is_empty() {
-			continue;
-		}
-		// find keywords
-		match patterns
-			.iter()
-			.find(|&&pattern| line_s.starts_with(pattern) && line_s.ends_with(':'))
-		{
-			Some(pattern) => {
-				use KeywordType::*;
+	reader
+		.lines()
+		.map(|line| String::from(line.unwrap().trim()))
+		.filter(|line| !line.is_empty()) // ignore empty lines
+		.for_each(|line| {
+			match patterns
+				.iter() // find keyword
+				.find(|&&pattern| line.starts_with(pattern) && line.ends_with(':'))
+			{
+				Some(pattern) => {
+					use KeywordType::*;
 
-				ctx.last_keyword_type = ctx.cur_keyword_type;
-				ctx.last_tag = ctx.cur_tag.clone();
-				ctx.cur_keyword_type = Some(keyword_type(&pattern));
-				ctx.cur_tag = pattern.replace(' ', "").replace(':', "");
+					ctx.last_keyword_type = ctx.cur_keyword_type;
+					ctx.last_tag = ctx.cur_tag.clone();
+					ctx.cur_keyword_type = Some(keyword_type(&pattern));
+					ctx.cur_tag = pattern.replace(' ', "").replace(':', "");
 
-				// remember question id
-				if let Some(QuestionStart) = ctx.cur_keyword_type {
-					ctx.cur_question_pre["id"] = line_s.replace(':', "").as_str().into();
-				};
+					// remember question id
+					if let Some(QuestionStart) = ctx.cur_keyword_type {
+						ctx.cur_question_pre["id"] = line.replace(':', "").as_str().into();
+					};
 
-				// apply accumulated content when new keyword found
-				match ctx.last_keyword_type {
-					Some(Global) => {
-						ctx.cur_scope = DataScope::Global;
-						ctx.data[&ctx.last_tag] = ctx.cur_content.join("\n").into()
-					}
-					Some(QuestionPre) => {
-						ctx.cur_scope = DataScope::QuestionPre;
-						ctx.cur_question_pre[&ctx.last_tag] = ctx.cur_content.join("\n").into();
-					}
-					Some(QuestionStart) => {
-						ctx.cur_scope = DataScope::QuestionContent;
-						// store prev question before reading new
-						if ctx.have_new_question {
-							ctx.questions.push(ctx.cur_question.clone()).unwrap();
+					// apply accumulated content when new keyword found
+					match ctx.last_keyword_type {
+						Some(Global) => {
+							ctx.cur_scope = DataScope::Global;
+							ctx.data[&ctx.last_tag] = ctx.cur_content.join("\n").into()
 						}
-						// prepare for read new question data with cur_question_pre values
-						ctx.cur_question = ctx.cur_question_pre.clone();
-						// ctx.cur_question_pre = json::JsonValue::new_object(); // uncomment => forget pre at new question
-						ctx.cur_question[&ctx.last_tag] = ctx.cur_content.join("\n").into();
-						ctx.have_new_question = true;
-					}
-					Some(QuestionContent) => {
-						ctx.cur_question[&ctx.last_tag] = ctx.cur_content.join("\n").into();
-					}
-					Some(CurrentScope) => {
-						// match value to store data
-						(match ctx.cur_scope {
-							DataScope::Global => &mut ctx.data,
-							DataScope::QuestionPre => &mut ctx.cur_question_pre,
-							DataScope::QuestionContent => &mut ctx.cur_question,
-						})[&ctx.last_tag] = ctx.cur_content.join("\n").into();
-					}
-					_ => (), //None or Ignore
-				};
-				// clear content
-				ctx.cur_content.clear();
+						Some(QuestionPre) => {
+							ctx.cur_scope = DataScope::QuestionPre;
+							ctx.cur_question_pre[&ctx.last_tag] = ctx.cur_content.join("\n").into();
+						}
+						Some(QuestionStart) => {
+							ctx.cur_scope = DataScope::QuestionContent;
+							// store prev question before reading new
+							if ctx.have_new_question {
+								ctx.questions.push(ctx.cur_question.clone()).unwrap();
+							}
+							// prepare for read new question data with cur_question_pre values
+							ctx.cur_question = ctx.cur_question_pre.clone();
+							// ctx.cur_question_pre = json::JsonValue::new_object(); // uncomment => forget pre at new question
+							ctx.cur_question[&ctx.last_tag] = ctx.cur_content.join("\n").into();
+							ctx.have_new_question = true;
+						}
+						Some(QuestionContent) => {
+							ctx.cur_question[&ctx.last_tag] = ctx.cur_content.join("\n").into();
+						}
+						Some(CurrentScope) => {
+							// match value to store data
+							(match ctx.cur_scope {
+								DataScope::Global => &mut ctx.data,
+								DataScope::QuestionPre => &mut ctx.cur_question_pre,
+								DataScope::QuestionContent => &mut ctx.cur_question,
+							})[&ctx.last_tag] = ctx.cur_content.join("\n").into();
+						}
+						_ => (), //None or Ignore
+					};
+					// clear content
+					ctx.cur_content.clear();
+				}
+				None => {
+					// accumulate content if line is not a keyword
+					ctx.cur_content.push(line);
+				}
 			}
-			None => {
-				// accumulate content if line is not a keyword
-				ctx.cur_content.push(String::from(line_s));
-			}
-		}
-	}
+		});
 
 	// finish reading last question
 	if ctx.have_new_question && !ctx.cur_content.is_empty() {