Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Syntax coloring lost after load or reformat #243

Open
norru opened this issue Apr 16, 2019 · 53 comments
Open

Syntax coloring lost after load or reformat #243

norru opened this issue Apr 16, 2019 · 53 comments
Labels
upstream-eclipse Issues requiring work on an Eclipse component (Platform, LSP4E...). Include link to upstream report!

Comments

@norru
Copy link
Contributor

norru commented Apr 16, 2019

I have observed Rust source syntax coloring loss occasionally, usually after:

  • first opening of a file
  • Ctrl+Shift+F formatting
  • copy/paste code from another source file

Closing and reopening the affected file is an effective, albeit annoying, workaround.

@mickaelistria mickaelistria added the upstream-eclipse Issues requiring work on an Eclipse component (Platform, LSP4E...). Include link to upstream report! label May 2, 2019
@mickaelistria
Copy link
Contributor

Seems like eclipse-tm4e/tm4e#203

@norru
Copy link
Contributor Author

norru commented May 2, 2019

I don't get that exception though.

@mickaelistria
Copy link
Contributor

Try http://download.eclipse.org/tm4e/snapshots/ which should reduce the chances for such problem to happen. It's still not perfect on TM4E side (it's not much tolerant to parallel changes such as editing when highlighting is computed), but it should be bette.r

@norru
Copy link
Contributor Author

norru commented May 8, 2019

I am already on the latest tm4e snapshot. Doesn't happen in older versions.

@mickaelistria
Copy link
Contributor

mickaelistria commented May 8, 2019 via email

@norru
Copy link
Contributor Author

norru commented May 8, 2019

Uhm, no. Eclipse says nothing new though. Perhaps the build hasn't made it to the update site?

@norru
Copy link
Contributor Author

norru commented May 8, 2019

Is this the one?

  TextMate Core	0.3.3.201905072152	tm-feature.feature.group	Angelo ZERR

@mickaelistria
Copy link
Contributor

mickaelistria commented May 8, 2019 via email

@norru
Copy link
Contributor Author

norru commented May 8, 2019

Yep. Pretty much all the time.

@mickaelistria
Copy link
Contributor

mickaelistria commented May 9, 2019 via email

@norru
Copy link
Contributor Author

norru commented May 9, 2019

org.eclipse.tm4e.core (0.3.3.201905072119) "TextMate support in Java" [Resolved]
org.eclipse.tm4e.languageconfiguration (0.3.3.201905072147) "TextMate support in Eclipse IDE - Language Configurations" [Resolved]
org.eclipse.tm4e.markdown (0.3.3.201905072152) "TextMate support in Eclipse IDE - Markdown" [Starting]
org.eclipse.tm4e.registry (0.3.3.201905072139) "TextMate support in Eclipse IDE - Registry management" [Resolved]
org.eclipse.tm4e.ui (0.3.3.201905072119) "TextMate support in Eclipse IDE - UI" [Active]
org.eclipse.tm4e.ui.editor (0.2.0.201809031154) "TextMate support in Eclipse IDE - Simple TextMate Editor" [Starting]

@norru
Copy link
Contributor Author

norru commented May 9, 2019

I have removed this one as it appears to be obsolete, no changes:

org.eclipse.tm4e.ui.editor (0.2.0.201809031154) "TextMate support in Eclipse IDE - Simple TextMate Editor" [Starting]

@mickaelistria
Copy link
Contributor

I tried another crappy hack to TM4E avoid interruption of the syntax highlighting thread in case of error. It's quite ugly, but it may help. Would you like to give it a try?

@norru
Copy link
Contributor Author

norru commented May 9, 2019

I could give it a shot, but what is exactly the problem? Is it a fundamental problem in how concurrency is handled? Can a "proper" solution for this issue be found for this issue or it is an architectural flaw?

@mickaelistria
Copy link
Contributor

mickaelistria commented May 9, 2019 via email

@norru
Copy link
Contributor Author

norru commented May 9, 2019

I don't know what is the root issue in your case,
the document changes while TM4E is trying to parse it

Uhm. My machine is very fast and powerful. If there is a race condition, it might have one of the branches win more often.

attempts to read a part of it that doesn't exist any more.

Shouldn't TM4E then try again when the document is not changing? How hard it is to add a hotkey to reparse manually? I'm not happy to have to close and reopen each document in the editor every time this happens (which is basically all the time right now).

@norru
Copy link
Contributor Author

norru commented May 9, 2019

Anyway, if there is something that can mitigate this, I'm ok to try it.

@mickaelistria
Copy link
Contributor

Shouldn't TM4E then try again when the document is not changing?

That's somehow what the last build should implement.

How hard it is to add a hotkey to reparse manually?

It's not hard, but it's a workaround. I don't have enough time to build or review workarounds when there are actual issues to fix ;)

@norru
Copy link
Contributor Author

norru commented May 9, 2019

@mickaelistria I have got a new TextMate Core snapshot about 15 minutes ago. So far it does look a bit better. Will keep testing throughout the day tomorrow and keep you posted. Thanks for now.

@norru
Copy link
Contributor Author

norru commented May 17, 2019

Still getting this quite often, about 50% frequency.

I've got two workarounds:

  • format in Eclipse, close and reopen editor
  • format externally via cargo fmt, reload from editor when Eclipse detects the change

Both are awfully annoying. To be fair, given the bad experience I've had in the last couple of months, I'm planning to give CLion another shot.

@norru
Copy link
Contributor Author

norru commented May 23, 2019

It's now ~100% again. It probably depends on the source file's length. Formatting in-editor is pretty much useless. I need to close and open editor windows again every single time I hit the format shortcut. If the file is large I lose track.

cargo fmt is the only viable workaround.

@norru
Copy link
Contributor Author

norru commented Jun 11, 2019

Problem seems less frequent with Eclipse 2019-06

@mickaelistria
Copy link
Contributor

I'm trying to work on it, but the lack of reproducer is really making it almost impossible to ensure fix works. Can you share an example project and minimal steps to reproduce it?

@mickaelistria
Copy link
Contributor

I've pushed a cleanup patch with some behavior enhancements to tm4e that might help. You can install the new build of TM4E from http://download.eclipse.org/tm4e/snapshots/ and maybe this will help.

@norru
Copy link
Contributor Author

norru commented Jun 12, 2019

I'm on Eclipse 2019-06 RC1 if it helps.

Can you share an example project and minimal steps to reproduce it?

Cannot share the project I'm working on but the problem is widespread. I think the problem is more frequent if the affected file is large (>1000 lines?)

@norru
Copy link
Contributor Author

norru commented Jul 1, 2019

Still open in Version: 2019-06 (4.12.0) Build id: 20190614-1200

@norru
Copy link
Contributor Author

norru commented Jul 1, 2019

If it helps, hitting Ctrl+Shift+F at the beginning of the file makes this issue less frequent than when the shortcut is hit near the bottom of the file.

@norru
Copy link
Contributor Author

norru commented Jul 2, 2019

Additional information: once this bug appears, syntax highlight stops working altogether for the affected editor, ie typing new code will always keep the code text black. The only workaround I found is to close and reopen the editor tab.

@norru
Copy link
Contributor Author

norru commented Jul 16, 2019

Still open in Corrosion 0.4.2.201907160841

@norru
Copy link
Contributor Author

norru commented Jul 16, 2019

@mickaelistria Steps to reproduce:

This is just an example. The problem is widespread and can be easily reproduced by loading any Rust project and attempting to edit any nontrivial file (the file in the example is ~250 lines long). I could not reproduce on very small files (<50 lines).

The problem may well be timing related so CPU speed may play a role (perhaps it's harder to reproduce in slower machines?).

@mickaelistria
Copy link
Contributor

Can't reproduce here. I agree it seems like CPU performance have an impact.
Can you please try https://hudson.eclipse.org/tm4e/job/snapshot/ ? An interesting patch was merged earlier today for a probably similar issue with Dart, so maybe the patch improves the state for Corrosion as well.

@norru
Copy link
Contributor Author

norru commented Jul 16, 2019

@mickaelistria I have got TextMate Core 0.3.4.201907151606 tm-feature.feature.group Angelo ZERR earlier today, does seem to be matching the latest build.

With this version I am no longer able to reproduce by simply adding/removing empty lines. However, the following would:

  1. clone and import https://github.com/itadinanta/rust-oids.git
  2. open src/app/main.rs in a Rust editor
  3. go to line 30
  4. add two tabs at the beginning of the line.
  5. Ctrl+Shift+F
  6. Repeat from 4 a few times

For some reasons, the bug now appears only if the formatting does not change the length of the file (number of lines).

In fact artificially adding a line before formatting could be a better workaround than close/reopen. EDIT: I have observed the bad behaviour again even if the formatting does not change the line count.

@norru
Copy link
Contributor Author

norru commented Jul 23, 2019

Update: the workaround detailed above makes #261 more frequent.

@norru
Copy link
Contributor Author

norru commented Aug 12, 2019

Still open on 2019-08-12.

  • can reproduce by adding lines (see above)
  • can reproduce by adding tabs (see above)

@norru
Copy link
Contributor Author

norru commented Aug 21, 2019

Still open on 2019-08-21 (after a flurry of lsp4j snapshot updates).

@mickaelistria
Copy link
Contributor

LSP4J or LSP4E aren't involved here, as mentioned in #243 (comment) only TM4E is to be fixed.
I'm still not able to reproduce this issue deterministically, so not able to fix it. I would suggest anyone interested in fixing it to get into the discussion on the TM4E ticket linked above.

@norru
Copy link
Contributor Author

norru commented Sep 26, 2019

Still open on 2019-09-26

@norru
Copy link
Contributor Author

norru commented Oct 31, 2019

Problem still visible but with reduced frequency on 2019-10-31

@norru
Copy link
Contributor Author

norru commented Jan 28, 2020

Still open on 2020-01-28, with high frequency.

@norru
Copy link
Contributor Author

norru commented Feb 18, 2020

As suggested by @mickaelistria I have managed to reproduce this with basically no effort (except for the SDK setup itself) in the Eclipse SDK.

I am puzzled by the difficulty other people are encountering when attempting to reproduce this.

I understand this bug can not be reproduced deterministically but this is its nature - it's probably a race condition which by nature cannot be triggered reliably. However, this bug is very frequent and very easy to reproduce.

image

Anyway, I have no idea how to proceed from here to track it :)

Besides, I have attempted to load in the tm4e and lsp4e projects but I am not able to get a clean build in the SDK. I can only work with Corrosion on its own.

image
@mickaelistria @Boereck Any suggestions?

@mickaelistria
Copy link
Contributor

Any suggestions?

To what precisely?

@norru
Copy link
Contributor Author

norru commented Feb 18, 2020

I need help on general directions on what the next steps could be in order to pinpoint the problem. I have no idea on where to start looking/tracing/placing breakpoints.

First of all, do I require to have the source code projects for Corrosion, lsp4e and tm4e all together? If yes, first of all I need to figure out how to get rid of all the errors. I've tried the target-platform files for all 3 projects but none produces a clear result.

I've got latest master of all 3.

@mickaelistria
Copy link
Contributor

I think the simplest is to

  1. Have only TM4E sources in your workspace
  2. Build your own target-platform which contains Corrosion snapshots

Then when doing "Run As > Eclipse application", you'll be able to put breakpoint into TM4E classes.
TM4E has some troubleshooting hints that may help you in this noble quest: https://github.com/eclipse/tm4e/blob/master/documentation/TROUBLESHOOTING.md

@norru
Copy link
Contributor Author

norru commented Feb 18, 2020

Enabling the settings above produced this dump while attempting to reproduce the problem. EDIT: the dump is generated on editor close, no dump produced when the error actually occurs.

package org.eclipse.tm4e.ui.text;

import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tm4e.core.grammar.IGrammar;
import org.eclipse.tm4e.core.registry.Registry;
import org.eclipse.tm4e.ui.text.TMPresentationReconciler;
import org.eclipse.tm4e.ui.themes.ITokenProvider;
import org.eclipse.tm4e.ui.themes.css.CSSTokenProvider;
import org.junit.Test;

public class TMPresentationReconcilerTest {

	@Test
	public void colorize() throws Exception {

		Display display = new Display();
		Shell shell = new Shell(display);
		TextViewer viewer = new TextViewer(shell, SWT.NONE);
		IDocument document = new Document();
		viewer.setDocument(document);
		document.set("use cgmath;\nuse core::resource;\nuse frontend::render::formats;\nuse frontend::render::RenderFactoryExt;\nuse frontend::render::Result;\nuse frontend::render::Style;\nuse gfx;\nuse gfx::state::ColorMask;\nuse gfx::state::{Blend, BlendChannel, BlendValue, Equation, Factor};\nuse gfx::traits::FactoryExt;\nuse std::result;\n\npub type PrimitiveIndex = i16;\npub type VertexIndex = u16;\n\ngfx_vertex_struct!(VertexPosNormal {\n	pos: [f32; 3] = \"a_Pos\",\n	normal: [f32; 3] = \"a_Normal\",\n	tangent: [f32; 3] = \"a_Tangent\",\n	tex_coord: [f32; 2] = \"a_TexCoord\",\n	primitive_index: PrimitiveIndex = \"a_PrimIndex\",\n});\n\npub type Vertex = VertexPosNormal;\n\nmacro_rules! new_vertex {\n	($pos:expr, $tex_coord:expr) => {\n		Vertex { pos: $pos, normal: [0., 0., 1.], tangent: [1., 0., 0.], tex_coord: $tex_coord, primitive_index: 0 }\n	};\n}\n\nimpl Default for VertexPosNormal {\n	fn default() -> Self { new_vertex!([0.; 3], [0.5, 0.5]) }\n}\n\nimpl VertexPosNormal {\n	pub fn new(pos: [f32; 3], tex_coord: [f32; 2]) -> VertexPosNormal { new_vertex!(pos, tex_coord) }\n}\n\npub type M44 = cgmath::Matrix4<f32>;\n\nconst MAX_NUM_TOTAL_LIGHTS: usize = 16;\nconst MAX_NUM_TOTAL_TRANSFORMS: usize = 256;\n\npub const PREMULT: Blend = Blend {\n	color: BlendChannel {\n		equation: Equation::Add,\n		source: Factor::One,\n		destination: Factor::OneMinus(BlendValue::SourceAlpha),\n	},\n	alpha: BlendChannel { equation: Equation::Add, source: Factor::One, destination: Factor::One },\n};\n\ngfx_defines!(\n	constant PointLight {\n		propagation: [f32; 4] = \"propagation\",\n		center: [f32; 4] = \"center\",\n		color: [f32; 4] = \"color\",\n	}\n\n	constant CameraArgs {\n		proj: [[f32; 4]; 4] = \"u_Proj\",\n		view: [[f32; 4]; 4] = \"u_View\",\n	}\n\n	constant ModelArgs {\n		transform: [[f32; 4]; 4] = \"transform\",\n	}\n\n	constant FragmentArgs {\n		light_count: i32 = \"u_LightCount\",\n	}\n\n	constant MaterialArgs {\n		emissive: [f32; 4] = \"u_Emissive\",\n		effect: [f32; 4] = \"u_Effect\",\n	}\n\n	pipeline shaded {\n		vbuf: gfx::VertexBuffer < VertexPosNormal > = (),\n		camera_args: gfx::ConstantBuffer < CameraArgs > = \"cb_CameraArgs\",\n		model_args: gfx::ConstantBuffer < ModelArgs> = \"u_ModelArgs\",\n		fragment_args: gfx::ConstantBuffer <FragmentArgs > = \"cb_FragmentArgs\",\n		material_args: gfx::ConstantBuffer< MaterialArgs > = \"cb_MaterialArgs\",\n		lights: gfx::ConstantBuffer < PointLight > = \"u_Lights\",\n		color_target: gfx::BlendTarget <formats::RenderColorFormat> = (\"o_Color\", ColorMask::all(), PREMULT),\n	depth_target: gfx::DepthTarget <formats::RenderDepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE,\n	}\n	/*\n		pipeline blend {\n			vbuf: gfx::VertexBuffer<VertexPosNormal> = (),\n			camera_args: gfx::ConstantBuffer<CameraArgs> = \"cb_CameraArgs\",\n			model_args: gfx::ConstantBuffer<ModelArgs> = \"cb_ModelArgs\",\n			fragment_args: gfx::ConstantBuffer<FragmentArgs> = \"cb_FragmentArgs\",\n			material_args: gfx::ConstantBuffer<MaterialArgs> = \"cb_MaterialArgs\",\n			lights: gfx::ConstantBuffer<PointLight> = \"u_Lights\",\n			color_target: gfx::BlendTarget<formats::RenderColorFormat> = (\"o_Color\", gfx::state::MASK_ALL, gfx::preset::blend::ALPHA),\n			depth_target: gfx::DepthTarget<formats::RenderDepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE,\n		}\n	*/\n\n);\n\npub type ShadedInit<'f> = shaded::Init<'f>;\n\nuse std::marker::PhantomData;\n\npub struct ForwardLighting<R: gfx::Resources, C: gfx::CommandBuffer<R>, D>\nwhere D: gfx::pso::PipelineInit {\n	camera: gfx::handle::Buffer<R, CameraArgs>,\n	model: gfx::handle::Buffer<R, ModelArgs>,\n	fragment: gfx::handle::Buffer<R, FragmentArgs>,\n	material: gfx::handle::Buffer<R, MaterialArgs>,\n	lights: gfx::handle::Buffer<R, PointLight>,\n	pso: [gfx::pso::PipelineState<R, D::Meta>; Style::Count as usize],\n	_buffer: PhantomData<C>,\n}\n\nimpl<R: gfx::Resources, C: gfx::CommandBuffer<R>, D> ForwardLighting<R, C, D>\nwhere D: gfx::pso::PipelineInit + Clone\n{\n	pub fn new<F>(\n		factory: &mut F,\n		res: &dyn resource::ResourceLoader<u8>,\n		init: D,\n	) -> Result<ForwardLighting<R, C, D>>\n	where\n		F: gfx::Factory<R>,\n	{\n		let lights = factory.create_constant_buffer(MAX_NUM_TOTAL_LIGHTS);\n		let camera = factory.create_constant_buffer(1);\n		let fragment = factory.create_constant_buffer(1);\n		let model = factory.create_constant_buffer(MAX_NUM_TOTAL_TRANSFORMS);\n		let material = factory.create_constant_buffer(MAX_NUM_TOTAL_TRANSFORMS);\n\n		macro_rules! load_shaders {\n			($v:expr, $f:expr) => {\n				factory.create_shader_set(\n					&res.load(concat!(\"shaders/forward/\", $v, \".vert\"))?,\n					&res.load(concat!(\"shaders/forward/\", $f, \".frag\"))?,\n					)\n			};\n\n			($g:expr, $v:expr, $f:expr) => {\n				factory.create_shader_set_with_geometry(\n					&res.load(concat!(\"shaders/forward/\", $g, \".geom\"))?,\n					&res.load(concat!(\"shaders/forward/\", $v, \".vert\"))?,\n					&res.load(concat!(\"shaders/forward/\", $f, \".frag\"))?,\n					)\n			};\n		};\n\n		let flat_shaders = load_shaders!(\"lighting\", \"lighting_flat\")?;\n		let wire_shaders = load_shaders!(\"lighting\", \"lighting_poly\")?;\n		let solid_shaders = load_shaders!(\"triangle_edge\", \"lighting\", \"lighting_poly\")?;\n		let stage_shaders = load_shaders!(\"lighting\", \"lighting_stage\")?;\n		let particle_shaders = load_shaders!(\"unlit\", \"ripple_particle\")?;\n		let ball_shaders = load_shaders!(\"point_ball\", \"lighting\", \"lighting_poly\")?;\n\n		let solid_rasterizer =\n			gfx::state::Rasterizer { samples: Some(gfx::state::MultiSample), ..gfx::state::Rasterizer::new_fill() };\n\n		let line_rasterizer = gfx::state::Rasterizer { method: gfx::state::RasterMethod::Line(2), ..solid_rasterizer };\n		let debug_line_rasterizer =\n			gfx::state::Rasterizer { method: gfx::state::RasterMethod::Line(1), ..solid_rasterizer };\n\n		let ball_pso =\n			Self::new_pso(factory, &ball_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let poly_pso =\n			Self::new_pso(factory, &solid_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let stage_pso =\n			Self::new_pso(factory, &stage_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let particle_pso =\n			Self::new_pso(factory, &particle_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let wireframe_pso =\n			Self::new_pso(factory, &wire_shaders, gfx::Primitive::TriangleList, line_rasterizer, init.clone())?;\n		let lit_pso =\n			Self::new_pso(factory, &solid_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let lines_pso = Self::new_pso(factory, &flat_shaders, gfx::Primitive::LineList, line_rasterizer, init.clone())?;\n		let debug_lines_pso =\n			Self::new_pso(factory, &flat_shaders, gfx::Primitive::LineList, debug_line_rasterizer, init)?;\n		Ok(ForwardLighting {\n			camera,\n			model,\n			fragment,\n			material,\n			lights,\n			pso: [ball_pso, poly_pso, stage_pso, particle_pso, wireframe_pso, lit_pso, lines_pso, debug_lines_pso],\n			_buffer: PhantomData,\n		})\n	}\n\n	fn new_pso<F>(\n		factory: &mut F,\n		shaders: &gfx::ShaderSet<R>,\n		primitive: gfx::Primitive,\n		rasterizer: gfx::state::Rasterizer,\n		init: D,\n	) -> result::Result<gfx::pso::PipelineState<R, D::Meta>, gfx::PipelineStateError<String>>\n	where\n		F: gfx::Factory<R>,\n	{\n		factory.create_pipeline_state(&shaders, primitive, rasterizer, init)\n	}\n\n	pub fn setup(\n		&self,\n		encoder: &mut gfx::Encoder<R, C>,\n		camera_projection: M44,\n	camera_view: M44,\n		lights: &[PointLight],\n	) -> Result<()>\n	{\n		let mut lights_buf = lights.to_owned();\n\n		let count = lights_buf.len();\n		while lights_buf.len() < MAX_NUM_TOTAL_LIGHTS {\n			lights_buf.push(PointLight {\n				propagation: [0., 0., 0., 0.],\n				color: [0., 0., 0., 0.],\n				center: [0., 0., 0., 0.],\n			})\n		}\n\n		encoder.update_buffer(&self.lights, &lights_buf[..], 0)?;\n		encoder.update_constant_buffer(&self.camera, &CameraArgs {\n			proj: camera_projection.into(),\n			view: camera_view.into(),\n		});\n		encoder.update_constant_buffer(&self.fragment, &FragmentArgs { light_count: count as i32 });\n		Ok(())\n	}\n}\n\nimpl<R: gfx::Resources, C: gfx::CommandBuffer<R>> ForwardLighting<R, C, shaded::Init<'static>> {\n#[allow(clippy::too_many_arguments)]\n	pub fn draw_primitives(\n		&self,\n		shader: Style,\n		encoder: &mut gfx::Encoder<R, C>,\n		vertices: gfx::handle::Buffer<R, VertexPosNormal>,\n		indices: &gfx::Slice<R>,\n		models: &[ModelArgs],\n		materials: &[MaterialArgs],\n		color_buffer: &gfx::handle::RenderTargetView<R, formats::RenderColorFormat>,\n		depth_buffer: &gfx::handle::DepthStencilView<R, formats::RenderDepthFormat>,\n	) -> Result<()>\n	{\n		encoder.update_buffer(&self.model, &models, 0)?;\n		encoder.update_buffer(&self.material, &materials, 0)?;\n		encoder.draw(indices, &self.pso[shader as usize], &shaded::Data {\n			vbuf: vertices,\n	fragment_args: self.fragment.clone(),\n			material_args: self.material.clone(),\n			camera_args: self.camera.clone(),\n			model_args: self.model.clone(),\n	lights: self.lights.clone(),\n			color_target: color_buffer.clone(),\n			depth_target: depth_buffer.clone(),\n		});\n		Ok(())\n	}\n}\n");

		TMPresentationReconciler reconciler = new TMPresentationReconciler();
		reconciler.setTokenProvider(getTokenProvider());
		reconciler.setGrammar(getGrammar());
		reconciler.install(viewer);

		document.replace(7126, 0, "\n");
		document.replace(7127, 0, "\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7127, 2, "");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7127, 0, "\n");
		document.replace(7128, 0, "\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7127, 2, "");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7840, 0, "\n");
		document.replace(7841, 0, "\n");
		document.replace(7842, 0, "\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7841, 3, "");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7539, 0, "\n");
		document.replace(7540, 0, "\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7540, 2, "");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7278, 0, "	");
		document.replace(7279, 0, "	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(7278, 44, "		let mut lights_buf = lights.to_owned();\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(8142, 0, "\n		");
		document.replace(8145, 0, "\n		");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(8143, 6, "");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6465, 0, "\n");
		document.replace(6466, 0, "\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6465, 2, "");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6563, 0, "	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6563, 24, "		Ok(ForwardLighting {\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6564, 0, "\n	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6563, 2, "");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6564, 0, "	");
		document.replace(6565, 0, "	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6563, 25, "		Ok(ForwardLighting {\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6328, 0, "	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(6326, 116, "		let lines_pso = Self::new_pso(factory, &flat_shaders, gfx::Primitive::LineList, line_rasterizer, init.clone())?;\n");
		viewer.invalidateTextPresentation(0, 0);
		viewer.invalidateTextPresentation(166, 8209);
		document.replace(3686, 0, "	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(3678, 79, "impl<R: gfx::Resources, C: gfx::CommandBuffer<R>, D> ForwardLighting<R, C, D>\n");
		viewer.invalidateTextPresentation(0, 0);
		viewer.invalidateTextPresentation(3687, 22);
		viewer.invalidateTextPresentation(166, 8209);
		document.replace(3960, 0, "	");
		viewer.invalidateTextPresentation(166, 8210);
		document.replace(3960, 1, "");
		document.replace(3959, 0, "	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(3957, 70, "		let lights = factory.create_constant_buffer(MAX_NUM_TOTAL_LIGHTS);\n");
		viewer.invalidateTextPresentation(0, 0);

		while (!shell.isDisposed()) {
		}
	}
	private static ITokenProvider getTokenProvider() {
		return new CSSTokenProvider(TMPresentationReconcilerTest.class.getResourceAsStream("Solarized-light.css"));
	}

	private static IGrammar getGrammar() {
		Registry registry = new Registry();
		try {
		String grammar="YouGrammar.tmLanguage";
			return registry.loadGrammarFromPathSync(grammar,TMPresentationReconcilerTest.class.getResourceAsStream(grammar));
		} catch (Exception e) {
			e.printStackTrace();
		return null;
		}
	}
}

@norru
Copy link
Contributor Author

norru commented Feb 18, 2020

Another example:

package org.eclipse.tm4e.ui.text;

import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tm4e.core.grammar.IGrammar;
import org.eclipse.tm4e.core.registry.Registry;
import org.eclipse.tm4e.ui.text.TMPresentationReconciler;
import org.eclipse.tm4e.ui.themes.ITokenProvider;
import org.eclipse.tm4e.ui.themes.css.CSSTokenProvider;
import org.junit.Test;

public class TMPresentationReconcilerTest {

	@Test
	public void colorize() throws Exception {

		Display display = new Display();
		Shell shell = new Shell(display);
		TextViewer viewer = new TextViewer(shell, SWT.NONE);
		IDocument document = new Document();
		viewer.setDocument(document);
		document.set("use cgmath;\nuse core::resource;\nuse frontend::render::formats;\nuse frontend::render::RenderFactoryExt;\nuse frontend::render::Result;\nuse frontend::render::Style;\nuse gfx;\nuse gfx::state::ColorMask;\nuse gfx::state::{Blend, BlendChannel, BlendValue, Equation, Factor};\nuse gfx::traits::FactoryExt;\nuse std::result;\n\npub type PrimitiveIndex = i16;\npub type VertexIndex = u16;\n\ngfx_vertex_struct!(VertexPosNormal {\n	pos: [f32; 3] = \"a_Pos\",\n	normal: [f32; 3] = \"a_Normal\",\n	tangent: [f32; 3] = \"a_Tangent\",\n	tex_coord: [f32; 2] = \"a_TexCoord\",\n	primitive_index: PrimitiveIndex = \"a_PrimIndex\",\n});\n\npub type Vertex = VertexPosNormal;\n\nmacro_rules! new_vertex {\n	($pos:expr, $tex_coord:expr) => {\n		Vertex { pos: $pos, normal: [0., 0., 1.], tangent: [1., 0., 0.], tex_coord: $tex_coord, primitive_index: 0 }\n	};\n}\n\nimpl Default for VertexPosNormal {\n	fn default() -> Self { new_vertex!([0.; 3], [0.5, 0.5]) }\n}\n\nimpl VertexPosNormal {\n	pub fn new(pos: [f32; 3], tex_coord: [f32; 2]) -> VertexPosNormal { new_vertex!(pos, tex_coord) }\n}\n\npub type M44 = cgmath::Matrix4<f32>;\n\nconst MAX_NUM_TOTAL_LIGHTS: usize = 16;\nconst MAX_NUM_TOTAL_TRANSFORMS: usize = 256;\n\npub const PREMULT: Blend = Blend {\n	color: BlendChannel {\n		equation: Equation::Add,\n		source: Factor::One,\n		destination: Factor::OneMinus(BlendValue::SourceAlpha),\n	},\n	alpha: BlendChannel { equation: Equation::Add, source: Factor::One, destination: Factor::One },\n};\n\ngfx_defines!(\n	constant PointLight {\n		propagation: [f32; 4] = \"propagation\",\n		center: [f32; 4] = \"center\",\n		color: [f32; 4] = \"color\",\n	}\n\n	constant CameraArgs {\n		proj: [[f32; 4]; 4] = \"u_Proj\",\n		view: [[f32; 4]; 4] = \"u_View\",\n	}\n\n	constant ModelArgs {\n		transform: [[f32; 4]; 4] = \"transform\",\n	}\n\n	constant FragmentArgs {\n		light_count: i32 = \"u_LightCount\",\n	}\n\n	constant MaterialArgs {\n		emissive: [f32; 4] = \"u_Emissive\",\n		effect: [f32; 4] = \"u_Effect\",\n	}\n\n	pipeline shaded {\n		vbuf: gfx::VertexBuffer < VertexPosNormal > = (),\n		camera_args: gfx::ConstantBuffer < CameraArgs > = \"cb_CameraArgs\",\n		model_args: gfx::ConstantBuffer < ModelArgs> = \"u_ModelArgs\",\n		fragment_args: gfx::ConstantBuffer <FragmentArgs > = \"cb_FragmentArgs\",\n		material_args: gfx::ConstantBuffer< MaterialArgs > = \"cb_MaterialArgs\",\n		lights: gfx::ConstantBuffer < PointLight > = \"u_Lights\",\n		color_target: gfx::BlendTarget <formats::RenderColorFormat> = (\"o_Color\", ColorMask::all(), PREMULT),\n	depth_target: gfx::DepthTarget <formats::RenderDepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE,\n	}\n	/*\n		pipeline blend {\n			vbuf: gfx::VertexBuffer<VertexPosNormal> = (),\n			camera_args: gfx::ConstantBuffer<CameraArgs> = \"cb_CameraArgs\",\n			model_args: gfx::ConstantBuffer<ModelArgs> = \"cb_ModelArgs\",\n			fragment_args: gfx::ConstantBuffer<FragmentArgs> = \"cb_FragmentArgs\",\n			material_args: gfx::ConstantBuffer<MaterialArgs> = \"cb_MaterialArgs\",\n			lights: gfx::ConstantBuffer<PointLight> = \"u_Lights\",\n			color_target: gfx::BlendTarget<formats::RenderColorFormat> = (\"o_Color\", gfx::state::MASK_ALL, gfx::preset::blend::ALPHA),\n			depth_target: gfx::DepthTarget<formats::RenderDepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE,\n		}\n	*/\n\n);\n\npub type ShadedInit<'f> = shaded::Init<'f>;\n\nuse std::marker::PhantomData;\n\npub struct ForwardLighting<R: gfx::Resources, C: gfx::CommandBuffer<R>, D>\nwhere D: gfx::pso::PipelineInit {\n	camera: gfx::handle::Buffer<R, CameraArgs>,\n	model: gfx::handle::Buffer<R, ModelArgs>,\n	fragment: gfx::handle::Buffer<R, FragmentArgs>,\n	material: gfx::handle::Buffer<R, MaterialArgs>,\n	lights: gfx::handle::Buffer<R, PointLight>,\n	pso: [gfx::pso::PipelineState<R, D::Meta>; Style::Count as usize],\n	_buffer: PhantomData<C>,\n}\n\nimpl<R: gfx::Resources, C: gfx::CommandBuffer<R>, D> ForwardLighting<R, C, D>\nwhere D: gfx::pso::PipelineInit + Clone\n{\n	pub fn new<F>(\n		factory: &mut F,\n		res: &dyn resource::ResourceLoader<u8>,\n		init: D,\n	) -> Result<ForwardLighting<R, C, D>>\n	where\n		F: gfx::Factory<R>,\n	{\n		let lights = factory.create_constant_buffer(MAX_NUM_TOTAL_LIGHTS);\n		let camera = factory.create_constant_buffer(1);\n		let fragment = factory.create_constant_buffer(1);\n		let model = factory.create_constant_buffer(MAX_NUM_TOTAL_TRANSFORMS);\n		let material = factory.create_constant_buffer(MAX_NUM_TOTAL_TRANSFORMS);\n\n		macro_rules! load_shaders {\n			($v:expr, $f:expr) => {\n				factory.create_shader_set(\n					&res.load(concat!(\"shaders/forward/\", $v, \".vert\"))?,\n					&res.load(concat!(\"shaders/forward/\", $f, \".frag\"))?,\n					)\n			};\n\n			($g:expr, $v:expr, $f:expr) => {\n				factory.create_shader_set_with_geometry(\n					&res.load(concat!(\"shaders/forward/\", $g, \".geom\"))?,\n					&res.load(concat!(\"shaders/forward/\", $v, \".vert\"))?,\n					&res.load(concat!(\"shaders/forward/\", $f, \".frag\"))?,\n					)\n			};\n		};\n\n		let flat_shaders = load_shaders!(\"lighting\", \"lighting_flat\")?;\n		let wire_shaders = load_shaders!(\"lighting\", \"lighting_poly\")?;\n		let solid_shaders = load_shaders!(\"triangle_edge\", \"lighting\", \"lighting_poly\")?;\n		let stage_shaders = load_shaders!(\"lighting\", \"lighting_stage\")?;\n		let particle_shaders = load_shaders!(\"unlit\", \"ripple_particle\")?;\n		let ball_shaders = load_shaders!(\"point_ball\", \"lighting\", \"lighting_poly\")?;\n\n		let solid_rasterizer =\n			gfx::state::Rasterizer { samples: Some(gfx::state::MultiSample), ..gfx::state::Rasterizer::new_fill() };\n\n		let line_rasterizer = gfx::state::Rasterizer { method: gfx::state::RasterMethod::Line(2), ..solid_rasterizer };\n		let debug_line_rasterizer =\n			gfx::state::Rasterizer { method: gfx::state::RasterMethod::Line(1), ..solid_rasterizer };\n\n		let ball_pso =\n			Self::new_pso(factory, &ball_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let poly_pso =\n			Self::new_pso(factory, &solid_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let stage_pso =\n			Self::new_pso(factory, &stage_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let particle_pso =\n			Self::new_pso(factory, &particle_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let wireframe_pso =\n			Self::new_pso(factory, &wire_shaders, gfx::Primitive::TriangleList, line_rasterizer, init.clone())?;\n		let lit_pso =\n			Self::new_pso(factory, &solid_shaders, gfx::Primitive::TriangleList, solid_rasterizer, init.clone())?;\n		let lines_pso = Self::new_pso(factory, &flat_shaders, gfx::Primitive::LineList, line_rasterizer, init.clone())?;\n		let debug_lines_pso =\n			Self::new_pso(factory, &flat_shaders, gfx::Primitive::LineList, debug_line_rasterizer, init)?;\n		Ok(ForwardLighting {\n			camera,\n			model,\n			fragment,\n			material,\n			lights,\n			pso: [ball_pso, poly_pso, stage_pso, particle_pso, wireframe_pso, lit_pso, lines_pso, debug_lines_pso],\n			_buffer: PhantomData,\n		})\n	}\n\n	fn new_pso<F>(\n		factory: &mut F,\n		shaders: &gfx::ShaderSet<R>,\n		primitive: gfx::Primitive,\n		rasterizer: gfx::state::Rasterizer,\n		init: D,\n	) -> result::Result<gfx::pso::PipelineState<R, D::Meta>, gfx::PipelineStateError<String>>\n	where\n		F: gfx::Factory<R>,\n	{\n		factory.create_pipeline_state(&shaders, primitive, rasterizer, init)\n	}\n\n	pub fn setup(\n		&self,\n		encoder: &mut gfx::Encoder<R, C>,\n		camera_projection: M44,\n	camera_view: M44,\n		lights: &[PointLight],\n	) -> Result<()>\n	{\n		let mut lights_buf = lights.to_owned();\n\n		let count = lights_buf.len();\n		while lights_buf.len() < MAX_NUM_TOTAL_LIGHTS {\n			lights_buf.push(PointLight {\n				propagation: [0., 0., 0., 0.],\n				color: [0., 0., 0., 0.],\n				center: [0., 0., 0., 0.],\n			})\n		}\n\n		encoder.update_buffer(&self.lights, &lights_buf[..], 0)?;\n		encoder.update_constant_buffer(&self.camera, &CameraArgs {\n			proj: camera_projection.into(),\n			view: camera_view.into(),\n		});\n		encoder.update_constant_buffer(&self.fragment, &FragmentArgs { light_count: count as i32 });\n		Ok(())\n	}\n}\n\nimpl<R: gfx::Resources, C: gfx::CommandBuffer<R>> ForwardLighting<R, C, shaded::Init<'static>> {\n#[allow(clippy::too_many_arguments)]\n	pub fn draw_primitives(\n		&self,\n		shader: Style,\n		encoder: &mut gfx::Encoder<R, C>,\n		vertices: gfx::handle::Buffer<R, VertexPosNormal>,\n		indices: &gfx::Slice<R>,\n		models: &[ModelArgs],\n		materials: &[MaterialArgs],\n		color_buffer: &gfx::handle::RenderTargetView<R, formats::RenderColorFormat>,\n		depth_buffer: &gfx::handle::DepthStencilView<R, formats::RenderDepthFormat>,\n	) -> Result<()>\n	{\n		encoder.update_buffer(&self.model, &models, 0)?;\n		encoder.update_buffer(&self.material, &materials, 0)?;\n		encoder.draw(indices, &self.pso[shader as usize], &shaded::Data {\n			vbuf: vertices,\n	fragment_args: self.fragment.clone(),\n			material_args: self.material.clone(),\n			camera_args: self.camera.clone(),\n			model_args: self.model.clone(),\n	lights: self.lights.clone(),\n			color_target: color_buffer.clone(),\n			depth_target: depth_buffer.clone(),\n		});\n		Ok(())\n	}\n}\n");

		TMPresentationReconciler reconciler = new TMPresentationReconciler();
		reconciler.setTokenProvider(getTokenProvider());
		reconciler.setGrammar(getGrammar());
		reconciler.install(viewer);

		document.replace(809, 0, "\n");
		document.replace(810, 0, "\n");
		document.replace(811, 0, "\n");
		document.replace(812, 0, "\n");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(810, 4, "");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(907, 0, "	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(907, 24, "impl VertexPosNormal {\n");
		viewer.invalidateTextPresentation(0, 0);

		while (!shell.isDisposed()) {
		}
	}
	private static ITokenProvider getTokenProvider() {
		return new CSSTokenProvider(TMPresentationReconcilerTest.class.getResourceAsStream("Solarized-light.css"));
	}

	private static IGrammar getGrammar() {
		Registry registry = new Registry();
		try {
		String grammar="YouGrammar.tmLanguage";
			return registry.loadGrammarFromPathSync(grammar,TMPresentationReconcilerTest.class.getResourceAsStream(grammar));
		} catch (Exception e) {
			e.printStackTrace();
		return null;
		}
	}
}

@norru
Copy link
Contributor Author

norru commented Feb 18, 2020

Here's a matching error/dump. Error reproduced by:

  • going to line 17
  • prepending a \t to pub type RenderSurtface<R> = {
  • hitting Ctrl+Shift+F

image

package org.eclipse.tm4e.ui.text;

import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tm4e.core.grammar.IGrammar;
import org.eclipse.tm4e.core.registry.Registry;
import org.eclipse.tm4e.ui.text.TMPresentationReconciler;
import org.eclipse.tm4e.ui.themes.ITokenProvider;
import org.eclipse.tm4e.ui.themes.css.CSSTokenProvider;
import org.junit.Test;

public class TMPresentationReconcilerTest {

	@Test
	public void colorize() throws Exception {

		Display display = new Display();
		Shell shell = new Shell(display);
		TextViewer viewer = new TextViewer(shell, SWT.NONE);
		IDocument document = new Document();
		viewer.setDocument(document);
		document.set("use core::color;\nuse gfx;\n\npub type Rgba = color::Rgba<f32>;\npub type Float4 = [f32; 4];\npub type Float = f32;\npub type RenderColorChannels = gfx::format::R16_G16_B16_A16;\npub type RenderColorFormat = (RenderColorChannels, gfx::format::Float);\npub type RenderDepthFormat = gfx::format::Depth;\n\npub type ScreenColorChannels = gfx::format::R8_G8_B8_A8;\n// Srgba8 broken on Linux\npub type ScreenColorFormat = (ScreenColorChannels, gfx::format::Unorm);\n// Srgba8 broken on Linux\npub type ScreenDepthFormat = gfx::format::Depth;\n\npub type RenderSurface<R> = (\n	gfx::handle::Texture<R, RenderColorChannels>,\n	gfx::handle::ShaderResourceView<R, Float4>,\n	gfx::handle::RenderTargetView<R, RenderColorFormat>,\n);\n\npub type DepthSurface<R> = (\n	gfx::handle::Texture<R, gfx::format::D24>,\n	gfx::handle::ShaderResourceView<R, Float>,\n	gfx::handle::DepthStencilView<R, RenderDepthFormat>,\n);\n\npub type RenderSurfaceWithDepth<R> = (\n	gfx::handle::ShaderResourceView<R, Float4>,\n	gfx::handle::RenderTargetView<R, RenderColorFormat>,\n	gfx::handle::DepthStencilView<R, RenderDepthFormat>,\n);\n\npub const MSAA_MODE: gfx::texture::AaMode = gfx::texture::AaMode::Multi(4);\n");

		TMPresentationReconciler reconciler = new TMPresentationReconciler();
		reconciler.setTokenProvider(getTokenProvider());
		reconciler.setGrammar(getGrammar());
		reconciler.install(viewer);

		document.replace(705, 0, "	");
		viewer.invalidateTextPresentation(0, 0);
		document.replace(705, 30, "pub type DepthSurface<R> = (\n");
		viewer.invalidateTextPresentation(0, 0);

		while (!shell.isDisposed()) {
		}
	}
	private static ITokenProvider getTokenProvider() {
		return new CSSTokenProvider(TMPresentationReconcilerTest.class.getResourceAsStream("Solarized-light.css"));
	}

	private static IGrammar getGrammar() {
		Registry registry = new Registry();
		try {
		String grammar="YouGrammar.tmLanguage";
			return registry.loadGrammarFromPathSync(grammar,TMPresentationReconcilerTest.class.getResourceAsStream(grammar));
		} catch (Exception e) {
			e.printStackTrace();
		return null;
		}
	}
}

@norru
Copy link
Contributor Author

norru commented Dec 30, 2020

Still open with Eclipse 2020-12 and matching Corrosion :(

@cplir-c
Copy link

cplir-c commented Jul 5, 2021

On the new june build of corrosion (1.2.1.202106081156) and eclipse 2020-12 doing Window -> Editor -> Split Editor (Vertical) for the first time since eclipse launch on a 200 line rust file results in the second pane consistently being uncolored. It also happens when I leave the vertical split open and restart eclipse.

@mickaelistria
Copy link
Contributor

On the new june build of corrosion (1.2.1.202106081156) and eclipse 2020-12 doing Window -> Editor -> Split Editor (Vertical) for the first time since eclipse launch on a 200 line rust file results in the second pane consistently being uncolored. It also happens when I leave the vertical split open and restart eclipse.

Please open a separate issue for that as it doesn't seem related to the original bug.

@akurtakov
Copy link
Member

There have been many fixes and improvements to tm4e so do you still face the issue with latest versions?

@norru
Copy link
Contributor Author

norru commented Jun 2, 2022

I haven't used Corrosion for a while, I'll give this a shot though.

@akurtakov
Copy link
Member

Closing due to lack of interest.

@norru
Copy link
Contributor Author

norru commented Aug 18, 2023

I have started using Corrosion again, this problem still occurs albeit slightly less frequently.

@norru norru reopened this Aug 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
upstream-eclipse Issues requiring work on an Eclipse component (Platform, LSP4E...). Include link to upstream report!
Projects
None yet
Development

No branches or pull requests

4 participants