Чтобы отличить визуальный перенос от сохранённого перевода строки, отключите перенос слов в текстовом редакторе и проверьте исходный текст. В этом руководстве для Mac объясняется, как выполнить эту проверку, почему браузерная вёрстка может вводить в заблуждение и что именно можно узнать из скопированного кода.

В чём разница между визуальным переносом и переводом строки?

Визуальный перенос происходит, когда браузер или редактор выводит текст на следующую строку отображения, чтобы он поместился в доступную ширину. Сохранённый перевод строки является частью самого текста. W3C различает мягкие переносы строк и принудительные переносы, которые могут возникать из-за сохранённых символов новой строки или границ блочных элементов. Обработка пробелов в CSS меняет представление текста, не изменяя данные исходного документа. Модуль CSS Text Level 3

Из-за этого, когда код отображается в нескольких строках, возможны три варианта: одна логическая строка перенесена; текст содержит отдельные логические строки; или структура страницы принудительно создаёт визуальный перенос. По одному снимку экрана нельзя надёжно определить, какой вариант имеет место.

Здесь под «авторским переводом строки» понимается символ новой строки, присутствующий в изучаемом исходном тексте. Само его наличие не говорит о том, кто его добавил: это мог сделать форматтер, процесс экспорта или другое преобразование. Практическая задача — определить, относится ли граница к тексту или только к его текущему отображению.

Как проверить код в настольном редакторе на Mac?

Для этой процедуры используйте Visual Studio Code. Если возможно, начните с исходного файла кода. Если у вас есть только общедоступная веб-страница, скопируйте нужный фрагмент кода в отдельный документ редактора, но считайте этот документ свидетельством о скопированном тексте, пока не сможете сравнить его с оригиналом.

Отключите перенос строк, не форматируя текст

  1. Откройте файл или скопированный фрагмент в VS Code.
  2. Когда редактор в фокусе, нажмите Option+Z, чтобы выполнить команду Toggle Word Wrap.
  3. Посмотрите, соединяется ли кажущееся продолжение с предыдущей строкой отображения и уходит ли оно дальше по горизонтали.
  4. Если перенос уже был отключён, переключите настройку ещё раз, чтобы сравнить оба состояния. Важна разница между двумя представлениями.

Microsoft указывает Option+Z как стандартное сочетание клавиш macOS для команды Toggle Word Wrap с идентификатором editor.action.toggleWordWrap. Если ваши сочетания клавиш отличаются, найдите эту команду в редакторе Keyboard Shortcuts. Справочник по стандартным сочетаниям клавиш

Если для editor.wordWrap задано значение on, VS Code переносит текст по ширине области просмотра редактора. Поэтому отключение переноса убирает такие визуальные продолжения. Граница, которая остаётся в том же неизменённом тексте, является границей логической строки, а не визуальным переносом в этом редакторе. Основы редактирования

Сравнивая представления, используйте эту таблицу решений:

Наблюдение Что оно подтверждает Следующее действие
При отключённом переносе продолжение соединяется с предыдущей строкой В редакторе это был визуальный перенос Оставьте текст без изменений
При отключённом переносе две строки остаются отдельными В проверяемом тексте есть граница строки Если вы проверяли копию, сравните её с оригиналом
Граница страницы исчезает в скопированном тексте Представление на странице отличается от скопированного Проверьте текст и структуру страницы
Скопированная граница сохраняется, но оригинала нет В скопированном тексте есть эта граница Не делайте выводов о её происхождении

Проверьте на искусственном примере

Вставьте следующий однострочный фрагмент в отдельный документ. Это иллюстративный текст на JavaScript; запускать его не нужно.

const labels = ["Amber", "Birch", "Cedar", "Dune", "Elm", "Fern", "Grove", "Harbor"];

Сузьте окно редактора так, чтобы текст перенёсся. При включённом переносе выражение может занимать несколько отображаемых строк. Отключите перенос: выражение должно снова отображаться как одна логическая строка, даже если для чтения её конца придётся прокрутить горизонтально.

Теперь сравните с намеренно многострочной версией:

const labels = [
  "Amber", "Birch", "Cedar", "Dune",
  "Elm", "Fern", "Grove", "Harbor"
];

Эти четыре логические строки остаются отдельными при отключённом переносе. При узкой ширине любая из них также может перенестись. Это и есть полезное различие: сохранённые переводы строки и визуальные переносы могут одновременно присутствовать в одном фрагменте кода.

Во время сравнения не форматируйте документ. Задача — изменить отображение, оставив проверяемый текст неизменным. Иначе изменившаяся граница строки может быть следствием редактирования, а не настройки отображения.

Почему изменение размера окна браузера — лишь предварительная проверка?

Представьте абстрактную общедоступную страницу с навигационной колонкой и панелью кода. Если расширить окно браузера, панели может достаться больше места. Если граница перемещается к другому слову, это подтверждает версию о переносе. Однако если ширина панели фиксирована, изменение размера внешнего окна может никак на неё не повлиять.

Поэтому неподвижная граница не позволяет сделать вывод. Возможно, браузер сохраняет символ новой строки, встречает структурную границу или переносит текст внутри панели, полезная ширина которой не изменилась. Проверьте текстовое представление, вместо того чтобы считать изменение размера окна доказательством.

CSS также определяет, видны ли сохранённые символы новой строки. MDN описывает следующие распространённые значения: свойство CSS white-space

Значение CSS Обработка символов новой строки в исходном тексте Автоматический перенос
normal Объединяются с другими пробельными символами Разрешён
pre Сохраняются Отключён
pre-wrap Сохраняются Разрешён
pre-line Сохраняются; пробелы и табуляции объединяются Разрешён

Следовательно, pre-wrap может одновременно отображать оба типа границ, а normal может скрывать символы новой строки из исходного текста. Отключить перенос с помощью nowrap недостаточно, чтобы проверить сохранность исходного текста, поскольку это свойство также объединяет пробельные символы. Для простого текстового блока, который вы контролируете, используйте pre для сравнения, если нужно сохранять пробельные символы, отключив автоматический перенос. свойство CSS white-space

Можно ли по скопированному тексту узнать исходные переводы строки?

Скопированный текст полезен, но это отдельное представление. MDN описывает innerText как отображаемый текст, приблизительно соответствующий тому, что получится при выделении и копировании элемента. Он учитывает отображение, включая явные разрывы, например элементы br. Поэтому наличие символа новой строки в вставленном фрагменте само по себе не доказывает, что он был в исходной строке кода. HTMLElement: свойство innerText

Для простого статического контейнера кода на другой вопрос отвечает textContent: оно возвращает текст узла и его потомков, объединяя текст потомков без учёта отображения. Это свойство удобно для проверки текста DOM, если контейнер действительно содержит нужный вам код. Node: свойство textContent

Эти свойства не взаимозаменяемы как средства восстановления исходного текста. Структурный разрыв не обязательно означает перевод строки в textContent; и наоборот, в исходном тексте могут быть пробельные символы, которые не отображаются как разрыв строки. Если текст страницы и её вёрстка не совпадают, точно описывайте результат: «текст DOM содержит символ новой строки», «вёрстка принудительно создаёт разрыв» или «в скопированной версии есть символ новой строки». Не утверждайте больше, чем позволяет установить проверенное представление.

Что меняется в браузерном редакторе кода?

Браузерный редактор может хранить документ отдельно от отображаемых элементов. Например, в официальной документации исходного кода CodeMirror описана модель Text, которая представляет строки документа: lines подсчитывает логические строки, а line(n) получает строку по номеру. Позиция to строки находится перед следующим за ней переводом строки или в конце документа. Документация API текста документа CodeMirror

CodeMirror также указывает, что его представление выводит в DOM только видимую часть кода и окружающее её поле. Свойство lineWrapping описывает перенос в представлении. Поэтому подсчёта отображаемых строк или извлечения видимой части DOM редактора недостаточно, чтобы определить все строки полного документа. Документация API представления редактора CodeMirror

Для обычной проверки на компьютере используйте документированную команду загрузки файла, экспорта или копирования в приложении, если она доступна, а затем проверьте результат с отключённым переносом. Если вы поддерживаете интеграцию с CodeMirror, используйте его модель документа для определения логических строк. Наличие API библиотеки не доказывает, что каждое приложение предоставляет соответствующую пользовательскую настройку.

Может ли форма добавить символы новой строки, которых никто не вводил?

Да. Стандарт HTML WHATWG различает текущее значение API текстовой области и представление, отправляемое формой. При wrap="soft" текст может визуально переноситься, но переносы не добавляются к отправляемому содержимому. При wrap="hard" в отправляемом представлении могут появиться разрывы строк; для этого необходимо задать cols. API нормализует окончания строк в LF. Стандарт HTML: элемент textarea

Это важно при сравнении текста до и после работы с формой. Если граница появляется только в отправленном или экспортированном результате, она могла возникнуть на этом этапе обработки. Проверяйте представление, которое соответствует вашей задаче: текущий текст редактора — чтобы определить введённые границы, или итоговый файл — чтобы узнать, что было экспортировано.

Как сохранить границы браузерной вёрстки и формирования текста?

Пусть браузер или редактор управляет визуальным переносом. W3C указывает, что overflow-wrap: anywhere сохраняет кластеры графем целыми и поддерживает формирование текста при добавленном переносе. Пересоздание строк путём вставки символов новой строки через фиксированное число символов не воспроизводит правила вёрстки. Модуль CSS Text Level 3

Если вы хотите повторно использовать фрагмент кода, сначала получите наилучший доступный исходник, сравните отображение с включённым и отключённым переносом и сохраните имеющиеся границы строк, если не планируете редактирование. Если доступна только отрисованная страница, зафиксируйте, что удалось установить об этом представлении, а неопределённые границы оставьте без однозначного вывода. Так вы получите воспроизводимую проверку и не превратите изменение отображения в случайное изменение текста.

Источники