Example #1
0
void log_frame::UpdateUI()
{
	std::vector<char> buf(4096);

	// Get UTF-8 string from file
	auto get_utf8 = [&](const fs::file& file, u64 size) -> QString
	{
		size = file.read(buf.data(), size);

		for (u64 i = 0; i < size; i++)
		{
			// Get UTF-8 sequence length (no real validation performed)
			const u64 tail =
				(buf[i] & 0xF0) == 0xF0 ? 3 :
				(buf[i] & 0xE0) == 0xE0 ? 2 :
				(buf[i] & 0xC0) == 0xC0 ? 1 : 0;

			if (i + tail >= size)
			{ // Copying is expensive-- O(i)-- but I suspect this corruption will be exceptionally unlikely.
				file.seek(i - size, fs::seek_cur);
				std::vector<char> sub(&buf[0], &buf[i]);
				return QString(sub.data());
			}
		}
		return QString(buf.data());
	};

	const auto start = steady_clock::now();

	// Check TTY logs

	while (const u64 size = std::min<u64>(buf.size(), m_tty_file.size() - m_tty_file.pos()))
	{
		QString text = get_utf8(m_tty_file, size);

		// Hackily used the state of the check..  be better if I actually stored this value.
		if (m_TTYAct->isChecked())
		{
			text.chop(1); // remove newline since Qt automatically adds a newline.
			m_tty->append(text);
		}
		// Limit processing time
		if (steady_clock::now() >= start + 4ms || text.isEmpty()) break;
	}

	// Check main logs
	while (const auto packet = s_gui_listener.read->next.load())
	{
		// Confirm log level
		if (packet->sev <= s_gui_listener.enabled)
		{
			QString text;
			switch (packet->sev)
			{
			case logs::level::always: break;
			case logs::level::fatal: text = "F "; break;
			case logs::level::error: text = "E "; break;
			case logs::level::todo: text = "U "; break;
			case logs::level::success: text = "S "; break;
			case logs::level::warning: text = "W "; break;
			case logs::level::notice: text = "! "; break;
			case logs::level::trace: text = "T "; break;
			default: continue;
			}

			// Print UTF-8 text.
			text += qstr(packet->msg);

			// save old log state
			QScrollBar *sb = m_log->verticalScrollBar();
			bool isMax = sb->value() == sb->maximum();
			int sb_pos = sb->value();
			int sel_pos = m_log->textCursor().position();
			int sel_start = m_log->textCursor().selectionStart();
			int sel_end = m_log->textCursor().selectionEnd();

			// clear selection or else it will get colorized as well
			QTextCursor c = m_log->textCursor();
			c.clearSelection();
			m_log->setTextCursor(c);

			// remove the new line because Qt's append adds a new line already.
			text.chop(1);

			QString suffix;
			bool isSame = text == m_old_text;

			// create counter suffix and remove recurring line if needed
			if (m_stack_log)
			{
				if (isSame)
				{
					m_log_counter++;
					suffix = QString(" x%1").arg(m_log_counter);
					m_log->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
					m_log->moveCursor(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
					m_log->moveCursor(QTextCursor::End, QTextCursor::KeepAnchor);
					m_log->textCursor().removeSelectedText();
					m_log->textCursor().deletePreviousChar();
				}
				else
				{
					m_log_counter = 1;
					m_old_text = text;
				}
			}

			// add actual log message
			m_log->setTextColor(m_color[static_cast<int>(packet->sev)]);
			m_log->append(text);

			// add counter suffix if needed
			if (m_stack_log && isSame)
			{
				m_log->setTextColor(m_color_stack);
				m_log->insertPlainText(suffix);
			}

			// if we mark text from right to left we need to swap sides (start is always smaller than end)
			if (sel_pos < sel_end)
			{
				std::swap(sel_start, sel_end);
			}

			// reset old text cursor and selection
			c.setPosition(sel_start);
			c.setPosition(sel_end, QTextCursor::KeepAnchor);
			m_log->setTextCursor(c);

			// set scrollbar to max means auto-scroll
			sb->setValue(isMax ? sb->maximum() : sb_pos);
		}

		// Drop packet
		s_gui_listener.pop();

		// Limit processing time
		if (steady_clock::now() >= start + 7ms) break;
	}
}
Example #2
0
void log_frame::UpdateUI()
{
	const auto start = steady_clock::now();

	// Check TTY logs
	while (const u64 size = std::max<s64>(0, g_tty_size.load() - m_tty_file.pos()))
	{
		std::string buf;
		buf.resize(size);
		buf.resize(m_tty_file.read(&buf.front(), buf.size()));

		if (buf.find_first_of('\0') != -1)
		{
			m_tty_file.seek(s64{0} - buf.size(), fs::seek_mode::seek_cur);
			break;
		}

		if (buf.size() && m_TTYAct->isChecked())
		{
			QTextCursor text_cursor{m_tty->document()};
			text_cursor.movePosition(QTextCursor::End);
			text_cursor.insertText(qstr(buf));
		}

		// Limit processing time
		if (steady_clock::now() >= start + 4ms || buf.empty()) break;
	}

	// Check main logs
	while (const auto packet = s_gui_listener.read->next.load())
	{
		// Confirm log level
		if (packet->sev <= s_gui_listener.enabled)
		{
			QString text;
			switch (packet->sev)
			{
			case logs::level::always: break;
			case logs::level::fatal: text = "F "; break;
			case logs::level::error: text = "E "; break;
			case logs::level::todo: text = "U "; break;
			case logs::level::success: text = "S "; break;
			case logs::level::warning: text = "W "; break;
			case logs::level::notice: text = "! "; break;
			case logs::level::trace: text = "T "; break;
			default: continue;
			}

			// Print UTF-8 text.
			text += qstr(packet->msg);

			// save old log state
			QScrollBar *sb = m_log->verticalScrollBar();
			bool isMax = sb->value() == sb->maximum();
			int sb_pos = sb->value();
			int sel_pos = m_log->textCursor().position();
			int sel_start = m_log->textCursor().selectionStart();
			int sel_end = m_log->textCursor().selectionEnd();

			// clear selection or else it will get colorized as well
			QTextCursor c = m_log->textCursor();
			c.clearSelection();
			m_log->setTextCursor(c);

			// remove the new line because Qt's append adds a new line already.
			text.chop(1);

			QString suffix;
			bool isSame = text == m_old_text;

			// create counter suffix and remove recurring line if needed
			if (m_stack_log)
			{
				if (isSame)
				{
					m_log_counter++;
					suffix = QString(" x%1").arg(m_log_counter);
					m_log->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
					m_log->moveCursor(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
					m_log->moveCursor(QTextCursor::End, QTextCursor::KeepAnchor);
					m_log->textCursor().removeSelectedText();
					m_log->textCursor().deletePreviousChar();
				}
				else
				{
					m_log_counter = 1;
					m_old_text = text;
				}
			}

			// add actual log message
			m_log->setTextColor(m_color[static_cast<int>(packet->sev)]);
			m_log->append(text);

			// add counter suffix if needed
			if (m_stack_log && isSame)
			{
				m_log->setTextColor(m_color_stack);
				m_log->insertPlainText(suffix);
			}

			// if we mark text from right to left we need to swap sides (start is always smaller than end)
			if (sel_pos < sel_end)
			{
				std::swap(sel_start, sel_end);
			}

			// reset old text cursor and selection
			c.setPosition(sel_start);
			c.setPosition(sel_end, QTextCursor::KeepAnchor);
			m_log->setTextCursor(c);

			// set scrollbar to max means auto-scroll
			sb->setValue(isMax ? sb->maximum() : sb_pos);
		}

		// Drop packet
		s_gui_listener.pop();

		// Limit processing time
		if (steady_clock::now() >= start + 7ms) break;
	}
}